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.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
20 import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
21 import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT;
22 import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
23 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
24 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
25 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
26 import static android.hardware.display.DisplayManager.EventsMask;
27 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
28 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
29 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
30 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP;
31 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
32 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
33 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
34 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
35 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
36 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
37 import static android.hardware.display.DisplayManagerGlobal.DisplayEvent;
38 import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL;
39 import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL;
40 import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL;
41 import static android.hardware.display.HdrConversionMode.HDR_CONVERSION_UNSUPPORTED;
42 import static android.os.Process.FIRST_APPLICATION_UID;
43 import static android.os.Process.ROOT_UID;
44 
45 import android.Manifest;
46 import android.annotation.NonNull;
47 import android.annotation.Nullable;
48 import android.annotation.RequiresPermission;
49 import android.annotation.SuppressLint;
50 import android.annotation.UserIdInt;
51 import android.app.ActivityManager;
52 import android.app.ActivityManagerInternal;
53 import android.app.AppOpsManager;
54 import android.app.compat.CompatChanges;
55 import android.companion.virtual.IVirtualDevice;
56 import android.companion.virtual.VirtualDeviceManager;
57 import android.compat.annotation.ChangeId;
58 import android.compat.annotation.EnabledSince;
59 import android.content.BroadcastReceiver;
60 import android.content.Context;
61 import android.content.Intent;
62 import android.content.IntentFilter;
63 import android.content.pm.PackageManager;
64 import android.content.pm.ParceledListSlice;
65 import android.content.res.Resources;
66 import android.content.res.TypedArray;
67 import android.database.ContentObserver;
68 import android.graphics.ColorSpace;
69 import android.graphics.Point;
70 import android.hardware.OverlayProperties;
71 import android.hardware.Sensor;
72 import android.hardware.SensorManager;
73 import android.hardware.devicestate.DeviceStateManager;
74 import android.hardware.devicestate.DeviceStateManagerInternal;
75 import android.hardware.display.AmbientBrightnessDayStats;
76 import android.hardware.display.BrightnessChangeEvent;
77 import android.hardware.display.BrightnessConfiguration;
78 import android.hardware.display.BrightnessInfo;
79 import android.hardware.display.Curve;
80 import android.hardware.display.DisplayManager;
81 import android.hardware.display.DisplayManagerGlobal;
82 import android.hardware.display.DisplayManagerInternal;
83 import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
84 import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
85 import android.hardware.display.DisplayViewport;
86 import android.hardware.display.DisplayedContentSample;
87 import android.hardware.display.DisplayedContentSamplingAttributes;
88 import android.hardware.display.HdrConversionMode;
89 import android.hardware.display.IDisplayManager;
90 import android.hardware.display.IDisplayManagerCallback;
91 import android.hardware.display.IVirtualDisplayCallback;
92 import android.hardware.display.VirtualDisplayConfig;
93 import android.hardware.display.WifiDisplayStatus;
94 import android.hardware.graphics.common.DisplayDecorationSupport;
95 import android.hardware.input.HostUsiVersion;
96 import android.media.projection.IMediaProjection;
97 import android.media.projection.IMediaProjectionManager;
98 import android.net.Uri;
99 import android.os.Binder;
100 import android.os.Handler;
101 import android.os.HandlerExecutor;
102 import android.os.IBinder;
103 import android.os.IBinder.DeathRecipient;
104 import android.os.Looper;
105 import android.os.Message;
106 import android.os.PowerManager;
107 import android.os.Process;
108 import android.os.RemoteException;
109 import android.os.ResultReceiver;
110 import android.os.ServiceManager;
111 import android.os.ShellCallback;
112 import android.os.SystemClock;
113 import android.os.SystemProperties;
114 import android.os.Trace;
115 import android.os.UserHandle;
116 import android.os.UserManager;
117 import android.provider.DeviceConfigInterface;
118 import android.provider.Settings;
119 import android.sysprop.DisplayProperties;
120 import android.text.TextUtils;
121 import android.util.ArraySet;
122 import android.util.EventLog;
123 import android.util.IntArray;
124 import android.util.Pair;
125 import android.util.Slog;
126 import android.util.SparseArray;
127 import android.util.SparseIntArray;
128 import android.util.Spline;
129 import android.view.ContentRecordingSession;
130 import android.view.Display;
131 import android.view.DisplayEventReceiver;
132 import android.view.DisplayInfo;
133 import android.view.Surface;
134 import android.view.SurfaceControl;
135 import android.view.SurfaceControl.RefreshRateRange;
136 import android.window.DisplayWindowPolicyController;
137 import android.window.ScreenCapture;
138 
139 import com.android.internal.annotations.GuardedBy;
140 import com.android.internal.annotations.VisibleForTesting;
141 import com.android.internal.display.BrightnessSynchronizer;
142 import com.android.internal.os.BackgroundThread;
143 import com.android.internal.util.ArrayUtils;
144 import com.android.internal.util.DumpUtils;
145 import com.android.internal.util.FrameworkStatsLog;
146 import com.android.internal.util.IndentingPrintWriter;
147 import com.android.internal.util.SettingsWrapper;
148 import com.android.server.AnimationThread;
149 import com.android.server.DisplayThread;
150 import com.android.server.LocalServices;
151 import com.android.server.SystemService;
152 import com.android.server.UiThread;
153 import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
154 import com.android.server.display.DisplayDeviceConfig.SensorData;
155 import com.android.server.display.feature.DeviceConfigParameterProvider;
156 import com.android.server.display.layout.Layout;
157 import com.android.server.display.mode.DisplayModeDirector;
158 import com.android.server.display.utils.SensorUtils;
159 import com.android.server.input.InputManagerInternal;
160 import com.android.server.utils.FoldSettingProvider;
161 import com.android.server.wm.SurfaceAnimationThread;
162 import com.android.server.wm.WindowManagerInternal;
163 
164 import java.io.FileDescriptor;
165 import java.io.PrintWriter;
166 import java.util.ArrayList;
167 import java.util.Arrays;
168 import java.util.List;
169 import java.util.Optional;
170 import java.util.Set;
171 import java.util.concurrent.CopyOnWriteArrayList;
172 import java.util.concurrent.atomic.AtomicLong;
173 import java.util.function.Consumer;
174 
175 
176 /**
177  * Manages attached displays.
178  * <p>
179  * The {@link DisplayManagerService} manages the global lifecycle of displays,
180  * decides how to configure logical displays based on the physical display devices currently
181  * attached, sends notifications to the system and to applications when the state
182  * changes, and so on.
183  * </p><p>
184  * The display manager service relies on a collection of {@link DisplayAdapter} components,
185  * for discovering and configuring physical display devices attached to the system.
186  * There are separate display adapters for each manner that devices are attached:
187  * one display adapter for physical displays, one for simulated non-functional
188  * displays when the system is headless, one for simulated overlay displays used for
189  * development, one for wifi displays, etc.
190  * </p><p>
191  * Display adapters are only weakly coupled to the display manager service.
192  * Display adapters communicate changes in display device state to the display manager
193  * service asynchronously via a {@link DisplayAdapter.Listener}, and through
194  * the {@link DisplayDeviceRepository.Listener}, which is ultimately registered
195  * by the display manager service.  This separation of concerns is important for
196  * two main reasons.  First, it neatly encapsulates the responsibilities of these
197  * two classes: display adapters handle individual display devices whereas
198  * the display manager service handles the global state.  Second, it eliminates
199  * the potential for deadlocks resulting from asynchronous display device discovery.
200  * </p>
201  *
202  * <h3>Synchronization</h3>
203  * <p>
204  * Because the display manager may be accessed by multiple threads, the synchronization
205  * story gets a little complicated.  In particular, the window manager may call into
206  * the display manager while holding a surface transaction with the expectation that
207  * it can apply changes immediately.  Unfortunately, that means we can't just do
208  * everything asynchronously (*grump*).
209  * </p><p>
210  * To make this work, all of the objects that belong to the display manager must
211  * use the same lock.  We call this lock the synchronization root and it has a unique
212  * type {@link DisplayManagerService.SyncRoot}.  Methods that require this lock are
213  * named with the "Locked" suffix.
214  * </p><p>
215  * Where things get tricky is that the display manager is not allowed to make
216  * any potentially reentrant calls, especially into the window manager.  We generally
217  * avoid this by making all potentially reentrant out-calls asynchronous.
218  * </p>
219  */
220 public final class DisplayManagerService extends SystemService {
221     private static final String TAG = "DisplayManagerService";
222     private static final boolean DEBUG = false;
223 
224     // When this system property is set to 0, WFD is forcibly disabled on boot.
225     // When this system property is set to 1, WFD is forcibly enabled on boot.
226     // Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
227     private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
228 
229     private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top";
230     private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
231     // This value needs to be in sync with the threshold
232     // in RefreshRateConfigs::getFrameRateDivisor.
233     private static final float THRESHOLD_FOR_REFRESH_RATES_DIVISORS = 0.0009f;
234 
235     private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
236     private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
237     private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
238     private static final int MSG_REQUEST_TRAVERSAL = 4;
239     private static final int MSG_UPDATE_VIEWPORT = 5;
240     private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATIONS = 6;
241     private static final int MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE = 7;
242     private static final int MSG_DELIVER_DISPLAY_GROUP_EVENT = 8;
243     private static final int MSG_RECEIVED_DEVICE_STATE = 9;
244     private static final int[] EMPTY_ARRAY = new int[0];
245     private static final HdrConversionMode HDR_CONVERSION_MODE_UNSUPPORTED = new HdrConversionMode(
246             HDR_CONVERSION_UNSUPPORTED);
247 
248     private final Context mContext;
249     private final DisplayManagerHandler mHandler;
250     private final Handler mUiHandler;
251     private final DisplayModeDirector mDisplayModeDirector;
252     private WindowManagerInternal mWindowManagerInternal;
253     private InputManagerInternal mInputManagerInternal;
254     private ActivityManagerInternal mActivityManagerInternal;
255     private ActivityManager mActivityManager;
256     private UidImportanceListener mUidImportanceListener = new UidImportanceListener();
257     @Nullable
258     private IMediaProjectionManager mProjectionService;
259     private DeviceStateManagerInternal mDeviceStateManager;
260     @GuardedBy("mSyncRoot")
261     private int[] mUserDisabledHdrTypes = {};
262     private int[] mSupportedHdrOutputType;
263     @GuardedBy("mSyncRoot")
264     private boolean mAreUserDisabledHdrTypesAllowed = true;
265 
266     // This value indicates whether or not HDR output control is enabled.
267     // It is read from DeviceConfig and is updated via a listener if the config changes.
268     private volatile boolean mIsHdrOutputControlEnabled;
269 
270     // Display mode chosen by user.
271     private Display.Mode mUserPreferredMode;
272     // HDR conversion mode chosen by user
273     @GuardedBy("mSyncRoot")
274     private HdrConversionMode mHdrConversionMode = null;
275     // Actual HDR conversion mode, which takes app overrides into account.
276     private HdrConversionMode mOverrideHdrConversionMode = null;
277     @GuardedBy("mSyncRoot")
278     private int mSystemPreferredHdrOutputType = Display.HdrCapabilities.HDR_TYPE_INVALID;
279 
280 
281     // The synchronization root for the display manager.
282     // This lock guards most of the display manager's state.
283     // NOTE: This is synchronized on while holding WindowManagerService.mWindowMap so never call
284     // into WindowManagerService methods that require mWindowMap while holding this unless you are
285     // very very sure that no deadlock can occur.
286     private final SyncRoot mSyncRoot = new SyncRoot();
287 
288     // True if in safe mode.
289     // This option may disable certain display adapters.
290     public boolean mSafeMode;
291 
292     // All callback records indexed by calling process id.
293     public final SparseArray<CallbackRecord> mCallbacks =
294             new SparseArray<CallbackRecord>();
295 
296     /**
297      *  All {@link IVirtualDevice} and {@link DisplayWindowPolicyController}s indexed by
298      *  {@link DisplayInfo#displayId}.
299      */
300     final SparseArray<Pair<IVirtualDevice, DisplayWindowPolicyController>>
301             mDisplayWindowPolicyControllers = new SparseArray<>();
302 
303     /**
304      * Provides {@link HighBrightnessModeMetadata}s for {@link DisplayDevice}s.
305      */
306     private final HighBrightnessModeMetadataMapper mHighBrightnessModeMetadataMapper =
307             new HighBrightnessModeMetadataMapper();
308 
309     // List of all currently registered display adapters.
310     private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
311 
312     /**
313      * Repository of all active {@link DisplayDevice}s.
314      */
315     private final DisplayDeviceRepository mDisplayDeviceRepo;
316 
317     /**
318      * Contains all the {@link LogicalDisplay} instances and is responsible for mapping
319      * {@link DisplayDevice}s to {@link LogicalDisplay}s. DisplayManagerService listens to display
320      * event on this object.
321      */
322     private final LogicalDisplayMapper mLogicalDisplayMapper;
323 
324     // List of all display transaction listeners.
325     private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners =
326             new CopyOnWriteArrayList<DisplayTransactionListener>();
327 
328     /** List of all display group listeners. */
329     private final CopyOnWriteArrayList<DisplayGroupListener> mDisplayGroupListeners =
330             new CopyOnWriteArrayList<>();
331 
332     /** All {@link DisplayPowerController}s indexed by {@link LogicalDisplay} ID. */
333     private final SparseArray<DisplayPowerControllerInterface> mDisplayPowerControllers =
334             new SparseArray<>();
335 
336     /** {@link DisplayBlanker} used by all {@link DisplayPowerController}s. */
337     private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() {
338         // Synchronized to avoid race conditions when updating multiple display states.
339         @Override
340         public synchronized void requestDisplayState(int displayId, int state, float brightness,
341                 float sdrBrightness) {
342             boolean allInactive = true;
343             boolean allOff = true;
344             final boolean stateChanged;
345             synchronized (mSyncRoot) {
346                 final int index = mDisplayStates.indexOfKey(displayId);
347                 if (index > -1) {
348                     final int currentState = mDisplayStates.valueAt(index);
349                     stateChanged = state != currentState;
350                     if (stateChanged) {
351                         final int size = mDisplayStates.size();
352                         for (int i = 0; i < size; i++) {
353                             final int displayState = i == index ? state : mDisplayStates.valueAt(i);
354                             if (displayState != Display.STATE_OFF) {
355                                 allOff = false;
356                             }
357                             if (Display.isActiveState(displayState)) {
358                                 allInactive = false;
359                             }
360                             if (!allOff && !allInactive) {
361                                 break;
362                             }
363                         }
364                     }
365                 } else {
366                     stateChanged = false;
367                 }
368             }
369 
370             // The order of operations is important for legacy reasons.
371             if (state == Display.STATE_OFF) {
372                 requestDisplayStateInternal(displayId, state, brightness, sdrBrightness);
373             }
374 
375             if (stateChanged) {
376                 mDisplayPowerCallbacks.onDisplayStateChange(allInactive, allOff);
377             }
378 
379             if (state != Display.STATE_OFF) {
380                 requestDisplayStateInternal(displayId, state, brightness, sdrBrightness);
381             }
382         }
383     };
384 
385     /**
386      * Used to inform {@link com.android.server.power.PowerManagerService} of changes to display
387      * state.
388      */
389     private DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks;
390 
391     /** The {@link Handler} used by all {@link DisplayPowerController}s. */
392     private Handler mPowerHandler;
393 
394     // A map from LogicalDisplay ID to display power state.
395     @GuardedBy("mSyncRoot")
396     private final SparseIntArray mDisplayStates = new SparseIntArray();
397 
398     // A map from LogicalDisplay ID to display brightness.
399     @GuardedBy("mSyncRoot")
400     private final SparseArray<BrightnessPair> mDisplayBrightnesses = new SparseArray<>();
401 
402     // Set to true when there are pending display changes that have yet to be applied
403     // to the surface flinger state.
404     private boolean mPendingTraversal;
405 
406     // The Wifi display adapter, or null if not registered.
407     private WifiDisplayAdapter mWifiDisplayAdapter;
408 
409     // The number of active wifi display scan requests.
410     private int mWifiDisplayScanRequestCount;
411 
412     // The virtual display adapter, or null if not registered.
413     private VirtualDisplayAdapter mVirtualDisplayAdapter;
414 
415     // The User ID of the current user
416     private @UserIdInt int mCurrentUserId;
417 
418     // The stable device screen height and width. These are not tied to a specific display, even
419     // the default display, because they need to be stable over the course of the device's entire
420     // life, even if the default display changes (e.g. a new monitor is plugged into a PC-like
421     // device).
422     private Point mStableDisplaySize = new Point();
423 
424     // Whether the system has finished booting or not.
425     private boolean mSystemReady;
426 
427     // The top inset of the default display.
428     // This gets persisted so that the boot animation knows how to transition from the display's
429     // full size to the size configured by the user. Right now we only persist and animate the top
430     // inset, but theoretically we could do it for all of them.
431     private int mDefaultDisplayTopInset;
432 
433     // Viewports of the default display and the display that should receive touch
434     // input from an external source.  Used by the input system.
435     @GuardedBy("mSyncRoot")
436     private final ArrayList<DisplayViewport> mViewports = new ArrayList<>();
437 
438     // Persistent data store for all internal settings maintained by the display manager service.
439     private final PersistentDataStore mPersistentDataStore = new PersistentDataStore();
440 
441     // Temporary callback list, used when sending display events to applications.
442     // May be used outside of the lock but only on the handler thread.
443     private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
444 
445     // Pending callback records indexed by calling process uid.
446     // Must be used outside of the lock mSyncRoot and should be selflocked.
447     @GuardedBy("mPendingCallbackSelfLocked")
448     public final SparseArray<PendingCallback> mPendingCallbackSelfLocked = new SparseArray<>();
449 
450     // Temporary viewports, used when sending new viewport information to the
451     // input system.  May be used outside of the lock but only on the handler thread.
452     private final ArrayList<DisplayViewport> mTempViewports = new ArrayList<>();
453 
454     // The default color mode for default displays. Overrides the usual
455     // Display.Display.COLOR_MODE_DEFAULT for local displays.
456     private final int mDefaultDisplayDefaultColorMode;
457 
458     // Lists of UIDs that are present on the displays. Maps displayId -> array of UIDs.
459     private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>();
460 
461     private final Injector mInjector;
462 
463     // The minimum brightness curve, which guarantess that any brightness curve that dips below it
464     // is rejected by the system.
465     private final Curve mMinimumBrightnessCurve;
466     private final Spline mMinimumBrightnessSpline;
467     private final ColorSpace mWideColorSpace;
468     private final OverlayProperties mOverlayProperties;
469 
470     private SensorManager mSensorManager;
471     private BrightnessTracker mBrightnessTracker;
472 
473     private SmallAreaDetectionController mSmallAreaDetectionController;
474 
475 
476     // Whether minimal post processing is allowed by the user.
477     @GuardedBy("mSyncRoot")
478     private boolean mMinimalPostProcessingAllowed;
479 
480     // Receives notifications about changes to Settings.
481     private SettingsObserver mSettingsObserver;
482 
483     // Keeps note of what state the device is in, used for idle screen brightness mode.
484     private boolean mIsDocked;
485     private boolean mIsDreaming;
486 
487     private boolean mBootCompleted = false;
488 
489     // If we would like to keep a particular eye on a package, we can set the package name.
490     private boolean mExtraDisplayEventLogging;
491 
492     private final BroadcastReceiver mIdleModeReceiver = new BroadcastReceiver() {
493         @Override
494         public void onReceive(Context context, Intent intent) {
495             final DisplayManagerInternal dmi =
496                     LocalServices.getService(DisplayManagerInternal.class);
497             if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
498                 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
499                         Intent.EXTRA_DOCK_STATE_UNDOCKED);
500                 mIsDocked = dockState == Intent.EXTRA_DOCK_STATE_DESK
501                         || dockState == Intent.EXTRA_DOCK_STATE_LE_DESK
502                         || dockState == Intent.EXTRA_DOCK_STATE_HE_DESK;
503             }
504             if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
505                 mIsDreaming = true;
506             } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
507                 mIsDreaming = false;
508             }
509             setDockedAndIdleEnabled(/* enabled= */(mIsDocked && mIsDreaming),
510                     Display.DEFAULT_DISPLAY);
511         }
512     };
513 
514     private final BrightnessSynchronizer mBrightnessSynchronizer;
515 
516     private final DeviceConfigParameterProvider mConfigParameterProvider;
517 
518     /**
519      * Applications use {@link android.view.Display#getRefreshRate} and
520      * {@link android.view.Display.Mode#getRefreshRate} to know what is the display refresh rate.
521      * Starting with Android S, the platform might throttle down applications frame rate to a
522      * divisor of the refresh rate if it is more preferable (for example if the application called
523      * to {@link android.view.Surface#setFrameRate}).
524      * Applications will experience {@link android.view.Choreographer#postFrameCallback} callbacks
525      * and backpressure at the throttled frame rate.
526      *
527      * {@link android.view.Display#getRefreshRate} will always return the application frame rate
528      * and not the physical display refresh rate to allow applications to do frame pacing correctly.
529      *
530      * {@link android.view.Display.Mode#getRefreshRate} will return the application frame rate if
531      * compiled to a previous release and starting with Android S it will return the physical
532      * display refresh rate.
533      */
534     @ChangeId
535     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
536     static final long DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE = 170503758L;
537 
DisplayManagerService(Context context)538     public DisplayManagerService(Context context) {
539         this(context, new Injector());
540     }
541 
542     @VisibleForTesting
DisplayManagerService(Context context, Injector injector)543     DisplayManagerService(Context context, Injector injector) {
544         super(context);
545         mInjector = injector;
546         mContext = context;
547         mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
548         mUiHandler = UiThread.getHandler();
549         mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
550         mLogicalDisplayMapper = new LogicalDisplayMapper(mContext,
551                 new FoldSettingProvider(mContext, new SettingsWrapper()), mDisplayDeviceRepo,
552                 new LogicalDisplayListener(), mSyncRoot, mHandler);
553         mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
554         mBrightnessSynchronizer = new BrightnessSynchronizer(mContext);
555         Resources resources = mContext.getResources();
556         mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
557                 com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
558         mDefaultDisplayTopInset = SystemProperties.getInt(PROP_DEFAULT_DISPLAY_TOP_INSET, -1);
559         float[] lux = getFloatArray(resources.obtainTypedArray(
560                 com.android.internal.R.array.config_minimumBrightnessCurveLux));
561         float[] nits = getFloatArray(resources.obtainTypedArray(
562                 com.android.internal.R.array.config_minimumBrightnessCurveNits));
563         mMinimumBrightnessCurve = new Curve(lux, nits);
564         mMinimumBrightnessSpline = Spline.createSpline(lux, nits);
565 
566         mCurrentUserId = UserHandle.USER_SYSTEM;
567         ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
568         mWideColorSpace = colorSpaces[1];
569         mOverlayProperties = SurfaceControl.getOverlaySupport();
570         mSystemReady = false;
571         mConfigParameterProvider = new DeviceConfigParameterProvider(DeviceConfigInterface.REAL);
572         final String name = DisplayProperties.debug_vri_package().orElse(null);
573         mExtraDisplayEventLogging = !TextUtils.isEmpty(name);
574     }
575 
setupSchedulerPolicies()576     public void setupSchedulerPolicies() {
577         // android.display and android.anim is critical to user experience and we should make sure
578         // it is not in the default foregroup groups, add it to top-app to make sure it uses all
579         // the cores and scheduling settings for top-app when it runs.
580         Process.setThreadGroupAndCpuset(DisplayThread.get().getThreadId(),
581                 Process.THREAD_GROUP_TOP_APP);
582         Process.setThreadGroupAndCpuset(AnimationThread.get().getThreadId(),
583                 Process.THREAD_GROUP_TOP_APP);
584         Process.setThreadGroupAndCpuset(SurfaceAnimationThread.get().getThreadId(),
585                 Process.THREAD_GROUP_TOP_APP);
586     }
587 
588     @Override
onStart()589     public void onStart() {
590         // We need to pre-load the persistent data store so it's ready before the default display
591         // adapter is up so that we have it's configuration. We could load it lazily, but since
592         // we're going to have to read it in eventually we may as well do it here rather than after
593         // we've waited for the display to register itself with us.
594         synchronized (mSyncRoot) {
595             mPersistentDataStore.loadIfNeeded();
596             loadStableDisplayValuesLocked();
597         }
598         mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);
599 
600         // If there was a runtime restart then we may have stale caches left around, so we need to
601         // make sure to invalidate them upon every start.
602         DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
603 
604         publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
605                 true /*allowIsolated*/);
606         publishLocalService(DisplayManagerInternal.class, new LocalService());
607     }
608 
609     @Override
onBootPhase(int phase)610     public void onBootPhase(int phase) {
611         if (phase == PHASE_WAIT_FOR_DEFAULT_DISPLAY) {
612             synchronized (mSyncRoot) {
613                 long timeout = SystemClock.uptimeMillis()
614                         + mInjector.getDefaultDisplayDelayTimeout();
615                 while (mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY) == null
616                         || mVirtualDisplayAdapter == null) {
617                     long delay = timeout - SystemClock.uptimeMillis();
618                     if (delay <= 0) {
619                         throw new RuntimeException("Timeout waiting for default display "
620                                 + "to be initialized. DefaultDisplay="
621                                 + mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY)
622                                 + ", mVirtualDisplayAdapter=" + mVirtualDisplayAdapter);
623                     }
624                     if (DEBUG) {
625                         Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
626                     }
627                     try {
628                         mSyncRoot.wait(delay);
629                     } catch (InterruptedException ex) {
630                     }
631                 }
632             }
633         } else if (phase == PHASE_BOOT_COMPLETED) {
634             synchronized (mSyncRoot) {
635                 mBootCompleted = true;
636                 for (int i = 0; i < mDisplayPowerControllers.size(); i++) {
637                     mDisplayPowerControllers.valueAt(i).onBootCompleted();
638                 }
639             }
640             mDisplayModeDirector.onBootCompleted();
641             mLogicalDisplayMapper.onBootCompleted();
642         }
643     }
644 
645     @Override
onUserSwitching(@ullable TargetUser from, @NonNull TargetUser to)646     public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
647         final int newUserId = to.getUserIdentifier();
648         final int userSerial = getUserManager().getUserSerialNumber(newUserId);
649         synchronized (mSyncRoot) {
650             boolean userSwitching = mCurrentUserId != newUserId;
651             if (userSwitching) {
652                 mCurrentUserId = newUserId;
653             }
654             mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
655                 if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
656                     return;
657                 }
658                 final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(
659                         logicalDisplay.getDisplayIdLocked());
660                 if (dpc == null) {
661                     return;
662                 }
663                 if (userSwitching) {
664                     BrightnessConfiguration config =
665                             getBrightnessConfigForDisplayWithPdsFallbackLocked(
666                             logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(),
667                             userSerial);
668                     dpc.setBrightnessConfiguration(config, /* shouldResetShortTermModel= */ true);
669                     // change the brightness value according to the selected user.
670                     final DisplayDevice device = logicalDisplay.getPrimaryDisplayDeviceLocked();
671                     if (device != null) {
672                         dpc.setBrightness(
673                                 mPersistentDataStore.getBrightness(device, userSerial), userSerial);
674                     }
675                 }
676                 dpc.onSwitchUser(newUserId);
677             });
678             handleSettingsChange();
679         }
680     }
681 
682     /**
683      * The 2nd stage initialization
684      * TODO: Use dependencies or a boot phase
685      */
686     @SuppressLint("AndroidFrameworkRequiresPermission")
windowManagerAndInputReady()687     public void windowManagerAndInputReady() {
688         synchronized (mSyncRoot) {
689             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
690             mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
691             mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
692             mActivityManager = mContext.getSystemService(ActivityManager.class);
693             mActivityManager.addOnUidImportanceListener(mUidImportanceListener, IMPORTANCE_CACHED);
694 
695             mDeviceStateManager = LocalServices.getService(DeviceStateManagerInternal.class);
696             mContext.getSystemService(DeviceStateManager.class).registerCallback(
697                     new HandlerExecutor(mHandler), new DeviceStateListener());
698 
699             scheduleTraversalLocked(false);
700         }
701     }
702 
703     /**
704      * Called when the system is ready to go.
705      */
systemReady(boolean safeMode)706     public void systemReady(boolean safeMode) {
707         synchronized (mSyncRoot) {
708             mSafeMode = safeMode;
709             mSystemReady = true;
710             mIsHdrOutputControlEnabled =
711                     mConfigParameterProvider.isHdrOutputControlFeatureEnabled();
712             mConfigParameterProvider.addOnPropertiesChangedListener(BackgroundThread.getExecutor(),
713                     properties -> mIsHdrOutputControlEnabled =
714                             mConfigParameterProvider.isHdrOutputControlFeatureEnabled());
715             // Just in case the top inset changed before the system was ready. At this point, any
716             // relevant configuration should be in place.
717             recordTopInsetLocked(mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY));
718 
719             updateSettingsLocked();
720             updateUserDisabledHdrTypesFromSettingsLocked();
721             updateUserPreferredDisplayModeSettingsLocked();
722             if (mIsHdrOutputControlEnabled) {
723                 updateHdrConversionModeSettingsLocked();
724             }
725         }
726 
727         mDisplayModeDirector.setDesiredDisplayModeSpecsListener(
728                 new DesiredDisplayModeSpecsObserver());
729         mDisplayModeDirector.start(mSensorManager);
730 
731         mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
732 
733         mSettingsObserver = new SettingsObserver();
734 
735         mBrightnessSynchronizer.startSynchronizing();
736 
737         final IntentFilter filter = new IntentFilter();
738         filter.addAction(Intent.ACTION_DREAMING_STARTED);
739         filter.addAction(Intent.ACTION_DREAMING_STOPPED);
740         filter.addAction(Intent.ACTION_DOCK_EVENT);
741 
742         mContext.registerReceiver(mIdleModeReceiver, filter);
743 
744         mSmallAreaDetectionController = SmallAreaDetectionController.create(mContext);
745     }
746 
747     @VisibleForTesting
getDisplayHandler()748     Handler getDisplayHandler() {
749         return mHandler;
750     }
751 
752     @VisibleForTesting
getDisplayDeviceRepository()753     DisplayDeviceRepository getDisplayDeviceRepository() {
754         return mDisplayDeviceRepo;
755     }
756 
757     @VisibleForTesting
isMinimalPostProcessingAllowed()758     boolean isMinimalPostProcessingAllowed() {
759         synchronized (mSyncRoot) {
760             return mMinimalPostProcessingAllowed;
761         }
762     }
763 
764     @VisibleForTesting
setMinimalPostProcessingAllowed(boolean allowed)765     void setMinimalPostProcessingAllowed(boolean allowed) {
766         synchronized (mSyncRoot) {
767             mMinimalPostProcessingAllowed = allowed;
768         }
769     }
770 
loadStableDisplayValuesLocked()771     private void loadStableDisplayValuesLocked() {
772         final Point size = mPersistentDataStore.getStableDisplaySize();
773         if (size.x > 0 && size.y > 0) {
774             // Just set these values directly so we don't write the display persistent data again
775             // unnecessarily
776             mStableDisplaySize.set(size.x, size.y);
777         } else {
778             final Resources res = mContext.getResources();
779             final int width = res.getInteger(
780                     com.android.internal.R.integer.config_stableDeviceDisplayWidth);
781             final int height = res.getInteger(
782                     com.android.internal.R.integer.config_stableDeviceDisplayHeight);
783             if (width > 0 && height > 0) {
784                 setStableDisplaySizeLocked(width, height);
785             }
786         }
787     }
788 
getStableDisplaySizeInternal()789     private Point getStableDisplaySizeInternal() {
790         Point r = new Point();
791         synchronized (mSyncRoot) {
792             if (mStableDisplaySize.x > 0 && mStableDisplaySize.y > 0) {
793                 r.set(mStableDisplaySize.x, mStableDisplaySize.y);
794             }
795         }
796         return r;
797     }
798 
registerDisplayTransactionListenerInternal( DisplayTransactionListener listener)799     private void registerDisplayTransactionListenerInternal(
800             DisplayTransactionListener listener) {
801         // List is self-synchronized copy-on-write.
802         mDisplayTransactionListeners.add(listener);
803     }
804 
unregisterDisplayTransactionListenerInternal( DisplayTransactionListener listener)805     private void unregisterDisplayTransactionListenerInternal(
806             DisplayTransactionListener listener) {
807         // List is self-synchronized copy-on-write.
808         mDisplayTransactionListeners.remove(listener);
809     }
810 
811     @VisibleForTesting
setDisplayInfoOverrideFromWindowManagerInternal(int displayId, DisplayInfo info)812     void setDisplayInfoOverrideFromWindowManagerInternal(int displayId, DisplayInfo info) {
813         synchronized (mSyncRoot) {
814             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
815             if (display != null) {
816                 if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
817                     handleLogicalDisplayChangedLocked(display);
818                 }
819             }
820         }
821     }
822 
823     /**
824      * @see DisplayManagerInternal#getNonOverrideDisplayInfo(int, DisplayInfo)
825      */
getNonOverrideDisplayInfoInternal(int displayId, DisplayInfo outInfo)826     private void getNonOverrideDisplayInfoInternal(int displayId, DisplayInfo outInfo) {
827         synchronized (mSyncRoot) {
828             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
829             if (display != null) {
830                 display.getNonOverrideDisplayInfoLocked(outInfo);
831             }
832         }
833     }
834 
835     @VisibleForTesting
performTraversalInternal(SurfaceControl.Transaction t)836     void performTraversalInternal(SurfaceControl.Transaction t) {
837         synchronized (mSyncRoot) {
838             if (!mPendingTraversal) {
839                 return;
840             }
841             mPendingTraversal = false;
842 
843             performTraversalLocked(t);
844         }
845 
846         // List is self-synchronized copy-on-write.
847         for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
848             listener.onDisplayTransaction(t);
849         }
850     }
851 
clampBrightness(int displayState, float brightnessState)852     private float clampBrightness(int displayState, float brightnessState) {
853         if (displayState == Display.STATE_OFF) {
854             brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT;
855         } else if (brightnessState != PowerManager.BRIGHTNESS_OFF_FLOAT
856                 && brightnessState < PowerManager.BRIGHTNESS_MIN) {
857             brightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
858         } else if (brightnessState > PowerManager.BRIGHTNESS_MAX) {
859             brightnessState = PowerManager.BRIGHTNESS_MAX;
860         }
861         return brightnessState;
862     }
863 
requestDisplayStateInternal(int displayId, int state, float brightnessState, float sdrBrightnessState)864     private void requestDisplayStateInternal(int displayId, int state, float brightnessState,
865             float sdrBrightnessState) {
866         if (state == Display.STATE_UNKNOWN) {
867             state = Display.STATE_ON;
868         }
869 
870         brightnessState = clampBrightness(state, brightnessState);
871         sdrBrightnessState = clampBrightness(state, sdrBrightnessState);
872 
873         // Update the display state within the lock.
874         // Note that we do not need to schedule traversals here although it
875         // may happen as a side-effect of displays changing state.
876         final Runnable runnable;
877         final String traceMessage;
878         synchronized (mSyncRoot) {
879             final int index = mDisplayStates.indexOfKey(displayId);
880 
881             final BrightnessPair brightnessPair =
882                     index < 0 ? null : mDisplayBrightnesses.valueAt(index);
883             if (index < 0 || (mDisplayStates.valueAt(index) == state
884                     && brightnessPair.brightness == brightnessState
885                     && brightnessPair.sdrBrightness == sdrBrightnessState)) {
886                 return; // Display no longer exists or no change.
887             }
888 
889             if (Trace.isTagEnabled(Trace.TRACE_TAG_POWER)) {
890                 traceMessage = Display.stateToString(state)
891                            + ", brightness=" + brightnessState
892                            + ", sdrBrightness=" + sdrBrightnessState;
893                 Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_POWER,
894                         "requestDisplayStateInternal:" + displayId,
895                         traceMessage, displayId);
896             }
897 
898             mDisplayStates.setValueAt(index, state);
899             brightnessPair.brightness = brightnessState;
900             brightnessPair.sdrBrightness = sdrBrightnessState;
901             runnable = updateDisplayStateLocked(mLogicalDisplayMapper.getDisplayLocked(displayId)
902                     .getPrimaryDisplayDeviceLocked());
903             if (Trace.isTagEnabled(Trace.TRACE_TAG_POWER)) {
904                 Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_POWER,
905                         "requestDisplayStateInternal:" + displayId, displayId);
906             }
907         }
908 
909         // Setting the display power state can take hundreds of milliseconds
910         // to complete so we defer the most expensive part of the work until
911         // after we have exited the critical section to avoid blocking other
912         // threads for a long time.
913         if (runnable != null) {
914             runnable.run();
915         }
916     }
917 
918     private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
919         @Override
920         public void onUidImportance(int uid, int importance) {
921             synchronized (mPendingCallbackSelfLocked) {
922                 if (importance >= IMPORTANCE_GONE) {
923                     // Clean up as the app is already gone
924                     Slog.d(TAG, "Drop pending events for gone uid " + uid);
925                     mPendingCallbackSelfLocked.delete(uid);
926                     return;
927                 } else if (importance >= IMPORTANCE_CACHED) {
928                     // Nothing to do as the app is still in cached mode
929                     return;
930                 }
931 
932                 // Do we care about this uid?
933                 PendingCallback pendingCallback = mPendingCallbackSelfLocked.get(uid);
934                 if (pendingCallback == null) {
935                     return;
936                 }
937 
938                 // Send the pending events out when a certain uid becomes non-cached
939                 if (DEBUG) {
940                     Slog.d(TAG, "Uid " + uid + " becomes " + importance);
941                 }
942                 pendingCallback.sendPendingDisplayEvent();
943                 mPendingCallbackSelfLocked.delete(uid);
944             }
945         }
946     }
947 
948     private class SettingsObserver extends ContentObserver {
SettingsObserver()949         SettingsObserver() {
950             super(mHandler);
951 
952             mContext.getContentResolver().registerContentObserver(
953                     Settings.Secure.getUriFor(
954                         Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED), false, this);
955         }
956 
957         @Override
onChange(boolean selfChange, Uri uri)958         public void onChange(boolean selfChange, Uri uri) {
959             handleSettingsChange();
960         }
961     }
962 
handleSettingsChange()963     private void handleSettingsChange() {
964         synchronized (mSyncRoot) {
965             updateSettingsLocked();
966             scheduleTraversalLocked(false);
967         }
968     }
969 
updateSettingsLocked()970     private void updateSettingsLocked() {
971         setMinimalPostProcessingAllowed(Settings.Secure.getIntForUser(
972                 mContext.getContentResolver(), Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED,
973                 1, UserHandle.USER_CURRENT) != 0);
974     }
975 
updateUserDisabledHdrTypesFromSettingsLocked()976     private void updateUserDisabledHdrTypesFromSettingsLocked() {
977         mAreUserDisabledHdrTypesAllowed = (Settings.Global.getInt(
978                 mContext.getContentResolver(),
979                 Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED,
980                 1) != 0);
981 
982         String userDisabledHdrTypes = Settings.Global.getString(mContext.getContentResolver(),
983                 Settings.Global.USER_DISABLED_HDR_FORMATS);
984 
985         if (userDisabledHdrTypes != null) {
986             try {
987                 String[] userDisabledHdrTypeStrings =
988                         TextUtils.split(userDisabledHdrTypes, ",");
989                 mUserDisabledHdrTypes = new int[userDisabledHdrTypeStrings.length];
990                 for (int i = 0; i < userDisabledHdrTypeStrings.length; i++) {
991                     mUserDisabledHdrTypes[i] = Integer.parseInt(userDisabledHdrTypeStrings[i]);
992                 }
993 
994                 if (!mAreUserDisabledHdrTypesAllowed) {
995                     mLogicalDisplayMapper.forEachLocked(
996                             display -> {
997                                 display.setUserDisabledHdrTypes(mUserDisabledHdrTypes);
998                                 handleLogicalDisplayChangedLocked(display);
999                             });
1000                 }
1001 
1002             } catch (NumberFormatException e) {
1003                 Slog.e(TAG, "Failed to parse USER_DISABLED_HDR_FORMATS. "
1004                         + "Clearing the setting.", e);
1005                 clearUserDisabledHdrTypesLocked();
1006             }
1007         } else {
1008             clearUserDisabledHdrTypesLocked();
1009         }
1010     }
1011 
clearUserDisabledHdrTypesLocked()1012     private void clearUserDisabledHdrTypesLocked() {
1013         synchronized (mSyncRoot) {
1014             mUserDisabledHdrTypes = new int[]{};
1015             Settings.Global.putString(mContext.getContentResolver(),
1016                     Settings.Global.USER_DISABLED_HDR_FORMATS, "");
1017         }
1018     }
1019 
updateUserPreferredDisplayModeSettingsLocked()1020     private void updateUserPreferredDisplayModeSettingsLocked() {
1021         final float refreshRate = Settings.Global.getFloat(mContext.getContentResolver(),
1022                 Settings.Global.USER_PREFERRED_REFRESH_RATE, Display.INVALID_DISPLAY_REFRESH_RATE);
1023         final int height = Settings.Global.getInt(mContext.getContentResolver(),
1024                 Settings.Global.USER_PREFERRED_RESOLUTION_HEIGHT, Display.INVALID_DISPLAY_HEIGHT);
1025         final int width = Settings.Global.getInt(mContext.getContentResolver(),
1026                 Settings.Global.USER_PREFERRED_RESOLUTION_WIDTH, Display.INVALID_DISPLAY_WIDTH);
1027         Display.Mode mode = new Display.Mode(width, height, refreshRate);
1028         mUserPreferredMode = isResolutionAndRefreshRateValid(mode) ? mode : null;
1029         if (mUserPreferredMode != null) {
1030             mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> {
1031                 device.setUserPreferredDisplayModeLocked(mode);
1032             });
1033         } else {
1034             mLogicalDisplayMapper.forEachLocked((LogicalDisplay display) -> {
1035                 configurePreferredDisplayModeLocked(display);
1036             });
1037         }
1038     }
1039 
getDisplayInfoForFrameRateOverride(DisplayEventReceiver.FrameRateOverride[] frameRateOverrides, DisplayInfo info, int callingUid)1040     private DisplayInfo getDisplayInfoForFrameRateOverride(DisplayEventReceiver.FrameRateOverride[]
1041             frameRateOverrides, DisplayInfo info, int callingUid) {
1042         float frameRateHz = info.renderFrameRate;
1043         for (DisplayEventReceiver.FrameRateOverride frameRateOverride : frameRateOverrides) {
1044             if (frameRateOverride.uid == callingUid) {
1045                 frameRateHz = frameRateOverride.frameRateHz;
1046                 break;
1047             }
1048         }
1049 
1050         if (frameRateHz == 0) {
1051             return info;
1052         }
1053 
1054         // For non-apps users we always return the physical refresh rate from display mode
1055         boolean displayModeReturnsPhysicalRefreshRate =
1056                 callingUid < FIRST_APPLICATION_UID
1057                         || CompatChanges.isChangeEnabled(
1058                                 DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE, callingUid);
1059 
1060         // Override the refresh rate only if it is a divisor of the current
1061         // refresh rate. This calculation needs to be in sync with the native code
1062         // in RefreshRateSelector::getFrameRateDivisor
1063         Display.Mode currentMode = info.getMode();
1064         float numPeriods = currentMode.getRefreshRate() / frameRateHz;
1065         float numPeriodsRound = Math.round(numPeriods);
1066         if (Math.abs(numPeriods - numPeriodsRound) > THRESHOLD_FOR_REFRESH_RATES_DIVISORS) {
1067             return info;
1068         }
1069         frameRateHz = currentMode.getRefreshRate() / numPeriodsRound;
1070 
1071         DisplayInfo overriddenInfo = new DisplayInfo();
1072         overriddenInfo.copyFrom(info);
1073         for (Display.Mode mode : info.supportedModes) {
1074             if (!mode.equalsExceptRefreshRate(currentMode)) {
1075                 continue;
1076             }
1077 
1078             if (mode.getRefreshRate() >= frameRateHz - THRESHOLD_FOR_REFRESH_RATES_DIVISORS
1079                     && mode.getRefreshRate()
1080                     <= frameRateHz + THRESHOLD_FOR_REFRESH_RATES_DIVISORS) {
1081                 if (DEBUG) {
1082                     Slog.d(TAG, "found matching modeId " + mode.getModeId());
1083                 }
1084                 overriddenInfo.refreshRateOverride = mode.getRefreshRate();
1085 
1086                 if (!displayModeReturnsPhysicalRefreshRate) {
1087                     overriddenInfo.modeId = mode.getModeId();
1088                 }
1089                 return overriddenInfo;
1090             }
1091         }
1092 
1093         overriddenInfo.refreshRateOverride = frameRateHz;
1094         if (!displayModeReturnsPhysicalRefreshRate) {
1095             overriddenInfo.supportedModes = Arrays.copyOf(info.supportedModes,
1096                     info.supportedModes.length + 1);
1097             overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1] =
1098                     new Display.Mode(Display.DISPLAY_MODE_ID_FOR_FRAME_RATE_OVERRIDE,
1099                             currentMode.getPhysicalWidth(), currentMode.getPhysicalHeight(),
1100                             overriddenInfo.refreshRateOverride,
1101                             new float[0], currentMode.getSupportedHdrTypes());
1102             overriddenInfo.modeId =
1103                     overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1]
1104                             .getModeId();
1105         }
1106         return overriddenInfo;
1107     }
1108 
getDisplayInfoInternal(int displayId, int callingUid)1109     private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
1110         synchronized (mSyncRoot) {
1111             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
1112             if (display != null) {
1113                 final DisplayInfo info =
1114                         getDisplayInfoForFrameRateOverride(display.getFrameRateOverrides(),
1115                                 display.getDisplayInfoLocked(), callingUid);
1116                 if (info.hasAccess(callingUid)
1117                         || isUidPresentOnDisplayInternal(callingUid, displayId)) {
1118                     return info;
1119                 }
1120             }
1121             return null;
1122         }
1123     }
1124 
registerCallbackInternal(IDisplayManagerCallback callback, int callingPid, int callingUid, @EventsMask long eventsMask)1125     private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid,
1126             int callingUid, @EventsMask long eventsMask) {
1127         synchronized (mSyncRoot) {
1128             CallbackRecord record = mCallbacks.get(callingPid);
1129 
1130             if (record != null) {
1131                 record.updateEventsMask(eventsMask);
1132                 return;
1133             }
1134 
1135             record = new CallbackRecord(callingPid, callingUid, callback, eventsMask);
1136             try {
1137                 IBinder binder = callback.asBinder();
1138                 binder.linkToDeath(record, 0);
1139             } catch (RemoteException ex) {
1140                 // give up
1141                 throw new RuntimeException(ex);
1142             }
1143 
1144             mCallbacks.put(callingPid, record);
1145         }
1146     }
1147 
onCallbackDied(CallbackRecord record)1148     private void onCallbackDied(CallbackRecord record) {
1149         synchronized (mSyncRoot) {
1150             mCallbacks.remove(record.mPid);
1151             stopWifiDisplayScanLocked(record);
1152         }
1153     }
1154 
startWifiDisplayScanInternal(int callingPid)1155     private void startWifiDisplayScanInternal(int callingPid) {
1156         synchronized (mSyncRoot) {
1157             CallbackRecord record = mCallbacks.get(callingPid);
1158             if (record == null) {
1159                 throw new IllegalStateException("The calling process has not "
1160                         + "registered an IDisplayManagerCallback.");
1161             }
1162             startWifiDisplayScanLocked(record);
1163         }
1164     }
1165 
startWifiDisplayScanLocked(CallbackRecord record)1166     private void startWifiDisplayScanLocked(CallbackRecord record) {
1167         if (!record.mWifiDisplayScanRequested) {
1168             record.mWifiDisplayScanRequested = true;
1169             if (mWifiDisplayScanRequestCount++ == 0) {
1170                 if (mWifiDisplayAdapter != null) {
1171                     mWifiDisplayAdapter.requestStartScanLocked();
1172                 }
1173             }
1174         }
1175     }
1176 
stopWifiDisplayScanInternal(int callingPid)1177     private void stopWifiDisplayScanInternal(int callingPid) {
1178         synchronized (mSyncRoot) {
1179             CallbackRecord record = mCallbacks.get(callingPid);
1180             if (record == null) {
1181                 throw new IllegalStateException("The calling process has not "
1182                         + "registered an IDisplayManagerCallback.");
1183             }
1184             stopWifiDisplayScanLocked(record);
1185         }
1186     }
1187 
stopWifiDisplayScanLocked(CallbackRecord record)1188     private void stopWifiDisplayScanLocked(CallbackRecord record) {
1189         if (record.mWifiDisplayScanRequested) {
1190             record.mWifiDisplayScanRequested = false;
1191             if (--mWifiDisplayScanRequestCount == 0) {
1192                 if (mWifiDisplayAdapter != null) {
1193                     mWifiDisplayAdapter.requestStopScanLocked();
1194                 }
1195             } else if (mWifiDisplayScanRequestCount < 0) {
1196                 Slog.wtf(TAG, "mWifiDisplayScanRequestCount became negative: "
1197                         + mWifiDisplayScanRequestCount);
1198                 mWifiDisplayScanRequestCount = 0;
1199             }
1200         }
1201     }
1202 
connectWifiDisplayInternal(String address)1203     private void connectWifiDisplayInternal(String address) {
1204         synchronized (mSyncRoot) {
1205             if (mWifiDisplayAdapter != null) {
1206                 mWifiDisplayAdapter.requestConnectLocked(address);
1207             }
1208         }
1209     }
1210 
pauseWifiDisplayInternal()1211     private void pauseWifiDisplayInternal() {
1212         synchronized (mSyncRoot) {
1213             if (mWifiDisplayAdapter != null) {
1214                 mWifiDisplayAdapter.requestPauseLocked();
1215             }
1216         }
1217     }
1218 
resumeWifiDisplayInternal()1219     private void resumeWifiDisplayInternal() {
1220         synchronized (mSyncRoot) {
1221             if (mWifiDisplayAdapter != null) {
1222                 mWifiDisplayAdapter.requestResumeLocked();
1223             }
1224         }
1225     }
1226 
disconnectWifiDisplayInternal()1227     private void disconnectWifiDisplayInternal() {
1228         synchronized (mSyncRoot) {
1229             if (mWifiDisplayAdapter != null) {
1230                 mWifiDisplayAdapter.requestDisconnectLocked();
1231             }
1232         }
1233     }
1234 
renameWifiDisplayInternal(String address, String alias)1235     private void renameWifiDisplayInternal(String address, String alias) {
1236         synchronized (mSyncRoot) {
1237             if (mWifiDisplayAdapter != null) {
1238                 mWifiDisplayAdapter.requestRenameLocked(address, alias);
1239             }
1240         }
1241     }
1242 
forgetWifiDisplayInternal(String address)1243     private void forgetWifiDisplayInternal(String address) {
1244         synchronized (mSyncRoot) {
1245             if (mWifiDisplayAdapter != null) {
1246                 mWifiDisplayAdapter.requestForgetLocked(address);
1247             }
1248         }
1249     }
1250 
getWifiDisplayStatusInternal()1251     private WifiDisplayStatus getWifiDisplayStatusInternal() {
1252         synchronized (mSyncRoot) {
1253             if (mWifiDisplayAdapter != null) {
1254                 return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
1255             }
1256             return new WifiDisplayStatus();
1257         }
1258     }
1259 
setUserDisabledHdrTypesInternal(int[] userDisabledHdrTypes)1260     private void setUserDisabledHdrTypesInternal(int[] userDisabledHdrTypes) {
1261         synchronized (mSyncRoot) {
1262             if (userDisabledHdrTypes == null) {
1263                 Slog.e(TAG, "Null is not an expected argument to "
1264                         + "setUserDisabledHdrTypesInternal");
1265                 return;
1266             }
1267 
1268             // Verify if userDisabledHdrTypes contains expected HDR types
1269             if (!isSubsetOf(Display.HdrCapabilities.HDR_TYPES, userDisabledHdrTypes)) {
1270                 Slog.e(TAG, "userDisabledHdrTypes contains unexpected types");
1271                 return;
1272             }
1273 
1274             Arrays.sort(userDisabledHdrTypes);
1275             if (Arrays.equals(mUserDisabledHdrTypes, userDisabledHdrTypes)) {
1276                 return;
1277             }
1278             String userDisabledFormatsString = "";
1279             if (userDisabledHdrTypes.length != 0) {
1280                 userDisabledFormatsString = TextUtils.join(",",
1281                         Arrays.stream(userDisabledHdrTypes).boxed().toArray());
1282             }
1283             Settings.Global.putString(mContext.getContentResolver(),
1284                     Settings.Global.USER_DISABLED_HDR_FORMATS, userDisabledFormatsString);
1285             mUserDisabledHdrTypes = userDisabledHdrTypes;
1286             if (!mAreUserDisabledHdrTypesAllowed) {
1287                 mLogicalDisplayMapper.forEachLocked(
1288                         display -> {
1289                             display.setUserDisabledHdrTypes(userDisabledHdrTypes);
1290                             handleLogicalDisplayChangedLocked(display);
1291                         });
1292             }
1293         }
1294     }
1295 
isSubsetOf(int[] sortedSuperset, int[] subset)1296     private boolean isSubsetOf(int[] sortedSuperset, int[] subset) {
1297         for (int i : subset) {
1298             if (Arrays.binarySearch(sortedSuperset, i) < 0) {
1299                 return false;
1300             }
1301         }
1302         return true;
1303     }
1304 
setAreUserDisabledHdrTypesAllowedInternal( boolean areUserDisabledHdrTypesAllowed)1305     private void setAreUserDisabledHdrTypesAllowedInternal(
1306             boolean areUserDisabledHdrTypesAllowed) {
1307         synchronized (mSyncRoot) {
1308             if (mAreUserDisabledHdrTypesAllowed == areUserDisabledHdrTypesAllowed) {
1309                 return;
1310             }
1311             mAreUserDisabledHdrTypesAllowed = areUserDisabledHdrTypesAllowed;
1312             if (mUserDisabledHdrTypes.length == 0) {
1313                 return;
1314             }
1315             Settings.Global.putInt(mContext.getContentResolver(),
1316                     Settings.Global.ARE_USER_DISABLED_HDR_FORMATS_ALLOWED,
1317                     areUserDisabledHdrTypesAllowed ? 1 : 0);
1318             int userDisabledHdrTypes[] = {};
1319             if (!mAreUserDisabledHdrTypesAllowed) {
1320                 userDisabledHdrTypes = mUserDisabledHdrTypes;
1321             }
1322             int[] finalUserDisabledHdrTypes = userDisabledHdrTypes;
1323             mLogicalDisplayMapper.forEachLocked(
1324                     display -> {
1325                         display.setUserDisabledHdrTypes(finalUserDisabledHdrTypes);
1326                         handleLogicalDisplayChangedLocked(display);
1327                     });
1328         }
1329     }
1330 
requestColorModeInternal(int displayId, int colorMode)1331     private void requestColorModeInternal(int displayId, int colorMode) {
1332         synchronized (mSyncRoot) {
1333             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
1334             if (display != null &&
1335                     display.getRequestedColorModeLocked() != colorMode) {
1336                 display.setRequestedColorModeLocked(colorMode);
1337                 scheduleTraversalLocked(false);
1338             }
1339         }
1340     }
1341 
validatePackageName(int uid, String packageName)1342     private boolean validatePackageName(int uid, String packageName) {
1343         // Root doesn't have a package name.
1344         if (uid == ROOT_UID) {
1345             return true;
1346         }
1347         if (packageName != null) {
1348             String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
1349             if (packageNames != null) {
1350                 for (String n : packageNames) {
1351                     if (n.equals(packageName)) {
1352                         return true;
1353                     }
1354                 }
1355             }
1356         }
1357         return false;
1358     }
1359 
canProjectVideo(IMediaProjection projection)1360     private boolean canProjectVideo(IMediaProjection projection) {
1361         if (projection != null) {
1362             try {
1363                 if (projection.canProjectVideo()) {
1364                     return true;
1365                 }
1366             } catch (RemoteException e) {
1367                 Slog.e(TAG, "Unable to query projection service for permissions", e);
1368             }
1369         }
1370         if (checkCallingPermission(CAPTURE_VIDEO_OUTPUT, "canProjectVideo()")) {
1371             return true;
1372         }
1373         return canProjectSecureVideo(projection);
1374     }
1375 
canProjectSecureVideo(IMediaProjection projection)1376     private boolean canProjectSecureVideo(IMediaProjection projection) {
1377         if (projection != null) {
1378             try {
1379                 if (projection.canProjectSecureVideo()) {
1380                     return true;
1381                 }
1382             } catch (RemoteException e) {
1383                 Slog.e(TAG, "Unable to query projection service for permissions", e);
1384             }
1385         }
1386         return checkCallingPermission(CAPTURE_SECURE_VIDEO_OUTPUT, "canProjectSecureVideo()");
1387     }
1388 
checkCallingPermission(String permission, String func)1389     private boolean checkCallingPermission(String permission, String func) {
1390         if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
1391             return true;
1392         }
1393         final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
1394                 + ", uid=" + Binder.getCallingUid() + " requires " + permission;
1395         Slog.w(TAG, msg);
1396         return false;
1397     }
1398 
createVirtualDisplayInternal(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, IVirtualDevice virtualDevice, DisplayWindowPolicyController dwpc, String packageName)1399     private int createVirtualDisplayInternal(VirtualDisplayConfig virtualDisplayConfig,
1400             IVirtualDisplayCallback callback, IMediaProjection projection,
1401             IVirtualDevice virtualDevice, DisplayWindowPolicyController dwpc, String packageName) {
1402         final int callingUid = Binder.getCallingUid();
1403         if (!validatePackageName(callingUid, packageName)) {
1404             throw new SecurityException("packageName must match the calling uid");
1405         }
1406         if (callback == null) {
1407             throw new IllegalArgumentException("appToken must not be null");
1408         }
1409         if (virtualDisplayConfig == null) {
1410             throw new IllegalArgumentException("virtualDisplayConfig must not be null");
1411         }
1412         final Surface surface = virtualDisplayConfig.getSurface();
1413         int flags = virtualDisplayConfig.getFlags();
1414         if (virtualDevice != null) {
1415             final VirtualDeviceManager vdm = mContext.getSystemService(VirtualDeviceManager.class);
1416             try {
1417                 if (!vdm.isValidVirtualDeviceId(virtualDevice.getDeviceId())) {
1418                     throw new SecurityException("Invalid virtual device");
1419                 }
1420             } catch (RemoteException ex) {
1421                 throw new SecurityException("Unable to validate virtual device");
1422             }
1423             final VirtualDeviceManagerInternal localVdm =
1424                     getLocalService(VirtualDeviceManagerInternal.class);
1425             flags |= localVdm.getBaseVirtualDisplayFlags(virtualDevice);
1426         }
1427 
1428         if (surface != null && surface.isSingleBuffered()) {
1429             throw new IllegalArgumentException("Surface can't be single-buffered");
1430         }
1431 
1432         if ((flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
1433             flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
1434 
1435             // Public displays can't be allowed to show content when locked.
1436             if ((flags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
1437                 throw new IllegalArgumentException(
1438                         "Public display must not be marked as SHOW_WHEN_LOCKED_INSECURE");
1439             }
1440         }
1441         if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
1442             flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
1443         }
1444         if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
1445             flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
1446         }
1447         if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) == 0 && virtualDevice != null) {
1448             flags |= VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP;
1449         }
1450 
1451         // Check if the host app is attempting to reuse the token or capture again on the same
1452         // MediaProjection instance. Don't start recording if so; MediaProjectionManagerService
1453         // decides how to respond based on the target SDK.
1454         boolean waitForPermissionConsent = false;
1455         final long firstToken = Binder.clearCallingIdentity();
1456         try {
1457             if (projection != null) {
1458                 if (!getProjectionService().isCurrentProjection(projection)) {
1459                     throw new SecurityException("Cannot create VirtualDisplay with "
1460                             + "non-current MediaProjection");
1461                 }
1462                 if (!projection.isValid()) {
1463                     // Just log; MediaProjectionManagerService throws an exception.
1464                     Slog.w(TAG, "Reusing token: create virtual display for app reusing token");
1465                     // If the exception wasn't thrown, we continue and re-show the permission dialog
1466                     getProjectionService().requestConsentForInvalidProjection(projection);
1467                     // Declare that mirroring shouldn't begin until user reviews the permission
1468                     // dialog.
1469                     waitForPermissionConsent = true;
1470                 }
1471                 flags = projection.applyVirtualDisplayFlags(flags);
1472             }
1473         } catch (RemoteException e) {
1474             throw new SecurityException("Unable to validate media projection or flags", e);
1475         } finally {
1476             Binder.restoreCallingIdentity(firstToken);
1477         }
1478 
1479         if (callingUid != Process.SYSTEM_UID
1480                 && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
1481             if (!canProjectVideo(projection)) {
1482                 throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
1483                         + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
1484                         + "MediaProjection token in order to create a screen sharing virtual "
1485                         + "display.");
1486             }
1487         }
1488         if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
1489             if (!canProjectSecureVideo(projection)) {
1490                 throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
1491                         + "or an appropriate MediaProjection token to create a "
1492                         + "secure virtual display.");
1493             }
1494         }
1495 
1496         if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
1497             if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
1498                 EventLog.writeEvent(0x534e4554, "162627132", callingUid,
1499                         "Attempt to create a trusted display without holding permission!");
1500                 throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
1501                         + "create a trusted virtual display.");
1502             }
1503         }
1504 
1505         if (callingUid != Process.SYSTEM_UID
1506                 && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
1507             // The virtualDevice instance has been validated above using isValidVirtualDevice
1508             if (virtualDevice == null
1509                     && !checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
1510                 throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
1511                         + "create a virtual display which is not in the default DisplayGroup.");
1512             }
1513         }
1514 
1515         if ((flags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0) {
1516             if (callingUid != Process.SYSTEM_UID
1517                     && !checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY,
1518                     "createVirtualDisplay()")) {
1519                 throw new SecurityException(
1520                         "Requires ADD_ALWAYS_UNLOCKED_DISPLAY permission to "
1521                                 + "create an always unlocked virtual display.");
1522             }
1523         }
1524 
1525         if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) {
1526             flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
1527         }
1528 
1529         // Sometimes users can have sensitive information in system decoration windows. An app
1530         // could create a virtual display with system decorations support and read the user info
1531         // from the surface.
1532         // We should only allow adding flag VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
1533         // to trusted virtual displays.
1534         final int trustedDisplayWithSysDecorFlag =
1535                 (VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
1536                         | VIRTUAL_DISPLAY_FLAG_TRUSTED);
1537         if ((flags & trustedDisplayWithSysDecorFlag)
1538                 == VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
1539                 && !checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "createVirtualDisplay()")) {
1540             throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
1541         }
1542 
1543         final long secondToken = Binder.clearCallingIdentity();
1544         try {
1545             final int displayId;
1546             synchronized (mSyncRoot) {
1547                 displayId =
1548                         createVirtualDisplayLocked(
1549                                 callback,
1550                                 projection,
1551                                 callingUid,
1552                                 packageName,
1553                                 virtualDevice,
1554                                 surface,
1555                                 flags,
1556                                 virtualDisplayConfig);
1557                 if (displayId != Display.INVALID_DISPLAY && virtualDevice != null && dwpc != null) {
1558                     mDisplayWindowPolicyControllers.put(
1559                             displayId, Pair.create(virtualDevice, dwpc));
1560                     Slog.d(TAG, "Virtual Display: successfully created virtual display");
1561                 }
1562             }
1563 
1564             // Build a session describing the MediaProjection instance, if there is one. A session
1565             // for a VirtualDisplay or physical display mirroring is handled in DisplayContent.
1566             ContentRecordingSession session = null;
1567             try {
1568                 if (projection != null) {
1569                     IBinder launchCookie = projection.getLaunchCookie();
1570                     if (launchCookie == null) {
1571                         // Record a particular display.
1572                         session = ContentRecordingSession.createDisplaySession(
1573                                 virtualDisplayConfig.getDisplayIdToMirror());
1574                     } else {
1575                         // Record a single task indicated by the launch cookie.
1576                         session = ContentRecordingSession.createTaskSession(launchCookie);
1577                     }
1578                 }
1579             } catch (RemoteException e) {
1580                 Slog.e(TAG, "Unable to retrieve the projection's launch cookie", e);
1581             }
1582 
1583             // Ensure session details are only set when mirroring (through VirtualDisplay flags or
1584             // MediaProjection).
1585             final boolean shouldMirror =
1586                     projection != null || (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0;
1587             // When calling WindowManagerService#setContentRecordingSession, WindowManagerService
1588             // attempts to acquire a lock before executing its main body. Due to this, we need
1589             // to be sure that it isn't called while the DisplayManagerService is also holding
1590             // a lock, to avoid a deadlock scenario.
1591             if (shouldMirror && displayId != Display.INVALID_DISPLAY && session != null) {
1592                 // Only attempt to set content recording session if there are details to set and a
1593                 // VirtualDisplay has been successfully constructed.
1594                 session.setVirtualDisplayId(displayId);
1595                 // Don't start mirroring until user re-grants consent.
1596                 session.setWaitingForConsent(waitForPermissionConsent);
1597 
1598                 // We set the content recording session here on the server side instead of using
1599                 // a second AIDL call in MediaProjection. By ensuring that a virtual display has
1600                 // been constructed before calling setContentRecordingSession, we avoid a race
1601                 // condition between the DisplayManagerService & WindowManagerService which could
1602                 // lead to the MediaProjection being pre-emptively torn down.
1603                 try {
1604                     if (!getProjectionService().setContentRecordingSession(session, projection)) {
1605                         // Unable to start mirroring, so release VirtualDisplay. Projection service
1606                         // handles stopping the projection.
1607                         Slog.w(TAG, "Content Recording: failed to start mirroring - "
1608                                 + "releasing virtual display " + displayId);
1609                         releaseVirtualDisplayInternal(callback.asBinder());
1610                         return Display.INVALID_DISPLAY;
1611                     } else if (projection != null) {
1612                         // Indicate that this projection has been used to record, and can't be used
1613                         // again.
1614                         Slog.d(TAG, "Content Recording: notifying MediaProjection of successful"
1615                                 + " VirtualDisplay creation.");
1616                         projection.notifyVirtualDisplayCreated(displayId);
1617                     }
1618                 } catch (RemoteException e) {
1619                     Slog.e(TAG, "Unable to tell MediaProjectionManagerService to set the "
1620                             + "content recording session", e);
1621                     return displayId;
1622                 }
1623                 Slog.d(TAG, "Virtual Display: successfully set up virtual display "
1624                         + displayId);
1625             }
1626             return displayId;
1627         } finally {
1628             Binder.restoreCallingIdentity(secondToken);
1629         }
1630     }
1631 
createVirtualDisplayLocked( IVirtualDisplayCallback callback, IMediaProjection projection, int callingUid, String packageName, IVirtualDevice virtualDevice, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig)1632     private int createVirtualDisplayLocked(
1633             IVirtualDisplayCallback callback,
1634             IMediaProjection projection,
1635             int callingUid,
1636             String packageName,
1637             IVirtualDevice virtualDevice,
1638             Surface surface,
1639             int flags,
1640             VirtualDisplayConfig virtualDisplayConfig) {
1641         if (mVirtualDisplayAdapter == null) {
1642             Slog.w(
1643                     TAG,
1644                     "Rejecting request to create private virtual display "
1645                             + "because the virtual display adapter is not available.");
1646             return -1;
1647         }
1648 
1649 
1650         Slog.d(TAG, "Virtual Display: creating DisplayDevice with VirtualDisplayAdapter");
1651         DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
1652                 callback, projection, callingUid, packageName, surface, flags,
1653                 virtualDisplayConfig);
1654         if (device == null) {
1655             Slog.w(TAG, "Virtual Display: VirtualDisplayAdapter failed to create DisplayDevice");
1656             return -1;
1657         }
1658 
1659         // If the display is to be added to a device display group, we need to make the
1660         // LogicalDisplayMapper aware of the link between the new display and its associated virtual
1661         // device before triggering DISPLAY_DEVICE_EVENT_ADDED.
1662         if ((flags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) {
1663             if (virtualDevice != null) {
1664                 try {
1665                     final int virtualDeviceId = virtualDevice.getDeviceId();
1666                     mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(
1667                             device, virtualDeviceId);
1668                 } catch (RemoteException e) {
1669                     e.rethrowFromSystemServer();
1670                 }
1671             } else {
1672                 Slog.i(
1673                         TAG,
1674                         "Display created with VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP set, but no"
1675                             + " virtual device. The display will not be added to a device display"
1676                             + " group.");
1677             }
1678         }
1679 
1680         // DisplayDevice events are handled manually for Virtual Displays.
1681         // TODO: multi-display Fix this so that generic add/remove events are not handled in a
1682         // different code path for virtual displays.  Currently this happens so that we can
1683         // return a valid display ID synchronously upon successful Virtual Display creation.
1684         // This code can run on any binder thread, while onDisplayDeviceAdded() callbacks are
1685         // called on the DisplayThread (which we don't want to wait for?).
1686         // One option would be to actually wait here on the binder thread
1687         // to be notified when the virtual display is created (or failed).
1688         mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
1689 
1690         final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
1691         if (display != null) {
1692             return display.getDisplayIdLocked();
1693         }
1694 
1695         // Something weird happened and the logical display was not created.
1696         Slog.w(TAG, "Rejecting request to create virtual display "
1697                 + "because the logical display was not created.");
1698         mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder());
1699         mDisplayDeviceRepo.onDisplayDeviceEvent(device,
1700                 DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
1701         return -1;
1702     }
1703 
resizeVirtualDisplayInternal(IBinder appToken, int width, int height, int densityDpi)1704     private void resizeVirtualDisplayInternal(IBinder appToken,
1705             int width, int height, int densityDpi) {
1706         synchronized (mSyncRoot) {
1707             if (mVirtualDisplayAdapter == null) {
1708                 return;
1709             }
1710 
1711             mVirtualDisplayAdapter.resizeVirtualDisplayLocked(appToken, width, height, densityDpi);
1712         }
1713     }
1714 
setVirtualDisplaySurfaceInternal(IBinder appToken, Surface surface)1715     private void setVirtualDisplaySurfaceInternal(IBinder appToken, Surface surface) {
1716         synchronized (mSyncRoot) {
1717             if (mVirtualDisplayAdapter == null) {
1718                 return;
1719             }
1720 
1721             mVirtualDisplayAdapter.setVirtualDisplaySurfaceLocked(appToken, surface);
1722         }
1723     }
1724 
releaseVirtualDisplayInternal(IBinder appToken)1725     private void releaseVirtualDisplayInternal(IBinder appToken) {
1726         synchronized (mSyncRoot) {
1727             if (mVirtualDisplayAdapter == null) {
1728                 return;
1729             }
1730 
1731             DisplayDevice device =
1732                     mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
1733             Slog.d(TAG, "Virtual Display: Display Device released");
1734             if (device != null) {
1735                 // TODO: multi-display - handle virtual displays the same as other display adapters.
1736                 mDisplayDeviceRepo.onDisplayDeviceEvent(device,
1737                         DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
1738             }
1739         }
1740     }
1741 
setVirtualDisplayStateInternal(IBinder appToken, boolean isOn)1742     private void setVirtualDisplayStateInternal(IBinder appToken, boolean isOn) {
1743         synchronized (mSyncRoot) {
1744             if (mVirtualDisplayAdapter == null) {
1745                 return;
1746             }
1747 
1748             mVirtualDisplayAdapter.setVirtualDisplayStateLocked(appToken, isOn);
1749         }
1750     }
1751 
registerDefaultDisplayAdapters()1752     private void registerDefaultDisplayAdapters() {
1753         // Register default display adapters.
1754         synchronized (mSyncRoot) {
1755             // main display adapter
1756             registerDisplayAdapterLocked(mInjector.getLocalDisplayAdapter(mSyncRoot, mContext,
1757                     mHandler, mDisplayDeviceRepo));
1758 
1759             // Standalone VR devices rely on a virtual display as their primary display for
1760             // 2D UI. We register virtual display adapter along side the main display adapter
1761             // here so that it is ready by the time the system sends the home Intent for
1762             // early apps like SetupWizard/Launcher. In particular, SUW is displayed using
1763             // the virtual display inside VR before any VR-specific apps even run.
1764             mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext,
1765                     mHandler, mDisplayDeviceRepo);
1766             if (mVirtualDisplayAdapter != null) {
1767                 registerDisplayAdapterLocked(mVirtualDisplayAdapter);
1768             }
1769         }
1770     }
1771 
registerAdditionalDisplayAdapters()1772     private void registerAdditionalDisplayAdapters() {
1773         synchronized (mSyncRoot) {
1774             if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
1775                 registerOverlayDisplayAdapterLocked();
1776                 registerWifiDisplayAdapterLocked();
1777             }
1778         }
1779     }
1780 
registerOverlayDisplayAdapterLocked()1781     private void registerOverlayDisplayAdapterLocked() {
1782         registerDisplayAdapterLocked(new OverlayDisplayAdapter(
1783                 mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mUiHandler));
1784     }
1785 
registerWifiDisplayAdapterLocked()1786     private void registerWifiDisplayAdapterLocked() {
1787         if (mContext.getResources().getBoolean(
1788                 com.android.internal.R.bool.config_enableWifiDisplay)
1789                 || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) {
1790             mWifiDisplayAdapter = new WifiDisplayAdapter(
1791                     mSyncRoot, mContext, mHandler, mDisplayDeviceRepo,
1792                     mPersistentDataStore);
1793             registerDisplayAdapterLocked(mWifiDisplayAdapter);
1794         }
1795     }
1796 
shouldRegisterNonEssentialDisplayAdaptersLocked()1797     private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
1798         // In safe mode, we disable non-essential display adapters to give the user
1799         // an opportunity to fix broken settings or other problems that might affect
1800         // system stability.
1801         return !mSafeMode;
1802     }
1803 
registerDisplayAdapterLocked(DisplayAdapter adapter)1804     private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
1805         mDisplayAdapters.add(adapter);
1806         adapter.registerLocked();
1807     }
1808 
handleLogicalDisplayAddedLocked(LogicalDisplay display)1809     private void handleLogicalDisplayAddedLocked(LogicalDisplay display) {
1810         final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
1811         final int displayId = display.getDisplayIdLocked();
1812         final boolean isDefault = displayId == Display.DEFAULT_DISPLAY;
1813         configureColorModeLocked(display, device);
1814         if (!mAreUserDisabledHdrTypesAllowed) {
1815             display.setUserDisabledHdrTypes(mUserDisabledHdrTypes);
1816         }
1817         if (isDefault) {
1818             notifyDefaultDisplayDeviceUpdated(display);
1819             recordStableDisplayStatsIfNeededLocked(display);
1820             recordTopInsetLocked(display);
1821         }
1822         if (mUserPreferredMode != null) {
1823             device.setUserPreferredDisplayModeLocked(mUserPreferredMode);
1824         } else {
1825             configurePreferredDisplayModeLocked(display);
1826         }
1827         DisplayPowerControllerInterface dpc = addDisplayPowerControllerLocked(display);
1828 
1829         if (dpc != null) {
1830             final int leadDisplayId = display.getLeadDisplayIdLocked();
1831             updateDisplayPowerControllerLeaderLocked(dpc, leadDisplayId);
1832 
1833             // Loop through all the displays and check if any should follow this one - it could be
1834             // that the follower display was added before the lead display.
1835             mLogicalDisplayMapper.forEachLocked(d -> {
1836                 if (d.getLeadDisplayIdLocked() == displayId) {
1837                     DisplayPowerControllerInterface followerDpc =
1838                             mDisplayPowerControllers.get(d.getDisplayIdLocked());
1839                     if (followerDpc != null) {
1840                         updateDisplayPowerControllerLeaderLocked(followerDpc, displayId);
1841                     }
1842                 }
1843             });
1844         }
1845 
1846         mDisplayStates.append(displayId, Display.STATE_UNKNOWN);
1847 
1848         final float brightnessDefault = display.getDisplayInfoLocked().brightnessDefault;
1849         mDisplayBrightnesses.append(displayId,
1850                 new BrightnessPair(brightnessDefault, brightnessDefault));
1851 
1852         DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
1853 
1854         // Wake up waitForDefaultDisplay.
1855         if (isDefault) {
1856             mSyncRoot.notifyAll();
1857         }
1858 
1859         sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
1860 
1861         Runnable work = updateDisplayStateLocked(device);
1862         if (work != null) {
1863             work.run();
1864         }
1865         scheduleTraversalLocked(false);
1866     }
1867 
handleLogicalDisplayChangedLocked(@onNull LogicalDisplay display)1868     private void handleLogicalDisplayChangedLocked(@NonNull LogicalDisplay display) {
1869         updateViewportPowerStateLocked(display);
1870 
1871         final int displayId = display.getDisplayIdLocked();
1872         if (displayId == Display.DEFAULT_DISPLAY) {
1873             recordTopInsetLocked(display);
1874         }
1875         // We don't bother invalidating the display info caches here because any changes to the
1876         // display info will trigger a cache invalidation inside of LogicalDisplay before we hit
1877         // this point.
1878         sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
1879         scheduleTraversalLocked(false);
1880         mPersistentDataStore.saveIfNeeded();
1881 
1882         DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
1883         if (dpc != null) {
1884             final int leadDisplayId = display.getLeadDisplayIdLocked();
1885             updateDisplayPowerControllerLeaderLocked(dpc, leadDisplayId);
1886 
1887             HighBrightnessModeMetadata hbmMetadata =
1888                     mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
1889             if (hbmMetadata != null) {
1890                 dpc.onDisplayChanged(hbmMetadata, leadDisplayId);
1891             }
1892         }
1893     }
1894 
updateDisplayPowerControllerLeaderLocked( @onNull DisplayPowerControllerInterface dpc, int leadDisplayId)1895     private void updateDisplayPowerControllerLeaderLocked(
1896             @NonNull DisplayPowerControllerInterface dpc, int leadDisplayId) {
1897         if (dpc.getLeadDisplayId() == leadDisplayId) {
1898             // Lead display hasn't changed, nothing to do.
1899             return;
1900         }
1901 
1902         // If it has changed, then we need to unregister from the previous leader if there was one.
1903         final int prevLeaderId = dpc.getLeadDisplayId();
1904         if (prevLeaderId != Layout.NO_LEAD_DISPLAY) {
1905             final DisplayPowerControllerInterface prevLeader =
1906                     mDisplayPowerControllers.get(prevLeaderId);
1907             if (prevLeader != null) {
1908                 prevLeader.removeDisplayBrightnessFollower(dpc);
1909             }
1910         }
1911 
1912         // And then, if it's following, register it with the new one.
1913         if (leadDisplayId != Layout.NO_LEAD_DISPLAY) {
1914             final DisplayPowerControllerInterface newLeader =
1915                     mDisplayPowerControllers.get(leadDisplayId);
1916             if (newLeader != null) {
1917                 newLeader.addDisplayBrightnessFollower(dpc);
1918             }
1919         }
1920     }
1921 
handleLogicalDisplayFrameRateOverridesChangedLocked( @onNull LogicalDisplay display)1922     private void handleLogicalDisplayFrameRateOverridesChangedLocked(
1923             @NonNull LogicalDisplay display) {
1924         final int displayId = display.getDisplayIdLocked();
1925         // We don't bother invalidating the display info caches here because any changes to the
1926         // display info will trigger a cache invalidation inside of LogicalDisplay before we hit
1927         // this point.
1928         sendDisplayEventFrameRateOverrideLocked(displayId);
1929         scheduleTraversalLocked(false);
1930     }
1931 
handleLogicalDisplayRemovedLocked(@onNull LogicalDisplay display)1932     private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
1933         final int displayId = display.getDisplayIdLocked();
1934         final DisplayPowerControllerInterface dpc =
1935                 mDisplayPowerControllers.removeReturnOld(displayId);
1936         if (dpc != null) {
1937             updateDisplayPowerControllerLeaderLocked(dpc, Layout.NO_LEAD_DISPLAY);
1938             dpc.stop();
1939         }
1940         mDisplayStates.delete(displayId);
1941         mDisplayBrightnesses.delete(displayId);
1942         DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
1943         sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
1944         scheduleTraversalLocked(false);
1945 
1946         if (mDisplayWindowPolicyControllers.contains(displayId)) {
1947             final IVirtualDevice virtualDevice = mDisplayWindowPolicyControllers.removeReturnOld(
1948                     displayId).first;
1949             if (virtualDevice != null) {
1950                 mHandler.post(() -> {
1951                     getLocalService(VirtualDeviceManagerInternal.class)
1952                             .onVirtualDisplayRemoved(virtualDevice, displayId);
1953                 });
1954             }
1955         }
1956     }
1957 
handleLogicalDisplaySwappedLocked(@onNull LogicalDisplay display)1958     private void handleLogicalDisplaySwappedLocked(@NonNull LogicalDisplay display) {
1959         handleLogicalDisplayChangedLocked(display);
1960 
1961         final int displayId = display.getDisplayIdLocked();
1962         if (displayId == Display.DEFAULT_DISPLAY) {
1963             notifyDefaultDisplayDeviceUpdated(display);
1964         }
1965         mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS);
1966     }
1967 
handleLogicalDisplayHdrSdrRatioChangedLocked(@onNull LogicalDisplay display)1968     private void handleLogicalDisplayHdrSdrRatioChangedLocked(@NonNull LogicalDisplay display) {
1969         sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED);
1970     }
1971 
notifyDefaultDisplayDeviceUpdated(LogicalDisplay display)1972     private void notifyDefaultDisplayDeviceUpdated(LogicalDisplay display) {
1973         mDisplayModeDirector.defaultDisplayDeviceUpdated(display.getPrimaryDisplayDeviceLocked()
1974                 .mDisplayDeviceConfig);
1975     }
1976 
handleLogicalDisplayDeviceStateTransitionLocked(@onNull LogicalDisplay display)1977     private void handleLogicalDisplayDeviceStateTransitionLocked(@NonNull LogicalDisplay display) {
1978         final int displayId = display.getDisplayIdLocked();
1979         final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
1980         if (dpc != null) {
1981             final int leadDisplayId = display.getLeadDisplayIdLocked();
1982             updateDisplayPowerControllerLeaderLocked(dpc, leadDisplayId);
1983 
1984             HighBrightnessModeMetadata hbmMetadata =
1985                     mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
1986             if (hbmMetadata != null) {
1987                 dpc.onDisplayChanged(hbmMetadata, leadDisplayId);
1988             }
1989         }
1990     }
1991 
updateDisplayStateLocked(DisplayDevice device)1992     private Runnable updateDisplayStateLocked(DisplayDevice device) {
1993         // Blank or unblank the display immediately to match the state requested
1994         // by the display power controller (if known).
1995         DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
1996         if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
1997             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
1998             if (display == null) {
1999                 return null;
2000             }
2001             final int displayId = display.getDisplayIdLocked();
2002             final int state = mDisplayStates.get(displayId);
2003 
2004             // Only send a request for display state if display state has already been initialized.
2005             if (state != Display.STATE_UNKNOWN) {
2006                 final BrightnessPair brightnessPair = mDisplayBrightnesses.get(displayId);
2007                 return device.requestDisplayStateLocked(state, brightnessPair.brightness,
2008                         brightnessPair.sdrBrightness);
2009             }
2010         }
2011         return null;
2012     }
2013 
configureColorModeLocked(LogicalDisplay display, DisplayDevice device)2014     private void configureColorModeLocked(LogicalDisplay display, DisplayDevice device) {
2015         if (display.getPrimaryDisplayDeviceLocked() == device) {
2016             int colorMode = mPersistentDataStore.getColorMode(device);
2017             if (colorMode == Display.COLOR_MODE_INVALID) {
2018                 if (display.getDisplayIdLocked() == Display.DEFAULT_DISPLAY) {
2019                     colorMode = mDefaultDisplayDefaultColorMode;
2020                 } else {
2021                     colorMode = Display.COLOR_MODE_DEFAULT;
2022                 }
2023             }
2024             display.setRequestedColorModeLocked(colorMode);
2025         }
2026     }
2027 
configurePreferredDisplayModeLocked(LogicalDisplay display)2028     private void configurePreferredDisplayModeLocked(LogicalDisplay display) {
2029         final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
2030         final Point userPreferredResolution =
2031                 mPersistentDataStore.getUserPreferredResolution(device);
2032         final float refreshRate = mPersistentDataStore.getUserPreferredRefreshRate(device);
2033         // If value in persistentDataStore is null, preserving the mode from systemPreferredMode.
2034         // This is required because in some devices, user-preferred mode was not stored in
2035         // persistentDataStore, but was stored in a config which is returned through
2036         // systemPreferredMode.
2037         if ((userPreferredResolution == null && Float.isNaN(refreshRate))
2038                 || (userPreferredResolution.equals(0, 0) && refreshRate == 0.0f)) {
2039             Display.Mode systemPreferredMode = device.getSystemPreferredDisplayModeLocked();
2040             if (systemPreferredMode == null) {
2041                 return;
2042             }
2043             storeModeInPersistentDataStoreLocked(
2044                     display.getDisplayIdLocked(), systemPreferredMode.getPhysicalWidth(),
2045                     systemPreferredMode.getPhysicalHeight(), systemPreferredMode.getRefreshRate());
2046             device.setUserPreferredDisplayModeLocked(systemPreferredMode);
2047             return;
2048         }
2049         Display.Mode.Builder modeBuilder = new Display.Mode.Builder();
2050         if (userPreferredResolution != null) {
2051             modeBuilder.setResolution(userPreferredResolution.x, userPreferredResolution.y);
2052         }
2053         if (!Float.isNaN(refreshRate)) {
2054             modeBuilder.setRefreshRate(refreshRate);
2055         }
2056         device.setUserPreferredDisplayModeLocked(modeBuilder.build());
2057     }
2058 
2059     @GuardedBy("mSyncRoot")
storeHdrConversionModeLocked(HdrConversionMode hdrConversionMode)2060     private void storeHdrConversionModeLocked(HdrConversionMode hdrConversionMode) {
2061         Settings.Global.putInt(mContext.getContentResolver(),
2062                 Settings.Global.HDR_CONVERSION_MODE, hdrConversionMode.getConversionMode());
2063         final int preferredHdrOutputType =
2064                 hdrConversionMode.getConversionMode() == HdrConversionMode.HDR_CONVERSION_FORCE
2065                         ? hdrConversionMode.getPreferredHdrOutputType()
2066                         : Display.HdrCapabilities.HDR_TYPE_INVALID;
2067         Settings.Global.putInt(mContext.getContentResolver(),
2068                 Settings.Global.HDR_FORCE_CONVERSION_TYPE, preferredHdrOutputType);
2069     }
2070 
2071     @GuardedBy("mSyncRoot")
updateHdrConversionModeSettingsLocked()2072     void updateHdrConversionModeSettingsLocked() {
2073         final int conversionMode = Settings.Global.getInt(mContext.getContentResolver(),
2074                 Settings.Global.HDR_CONVERSION_MODE, HdrConversionMode.HDR_CONVERSION_SYSTEM);
2075         final int preferredHdrOutputType = conversionMode == HdrConversionMode.HDR_CONVERSION_FORCE
2076                 ? Settings.Global.getInt(mContext.getContentResolver(),
2077                 Settings.Global.HDR_FORCE_CONVERSION_TYPE,
2078                         Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION)
2079                 : Display.HdrCapabilities.HDR_TYPE_INVALID;
2080         mHdrConversionMode = new HdrConversionMode(conversionMode, preferredHdrOutputType);
2081         setHdrConversionModeInternal(mHdrConversionMode);
2082     }
2083 
2084     // If we've never recorded stable device stats for this device before and they aren't
2085     // explicitly configured, go ahead and record the stable device stats now based on the status
2086     // of the default display at first boot.
recordStableDisplayStatsIfNeededLocked(LogicalDisplay d)2087     private void recordStableDisplayStatsIfNeededLocked(LogicalDisplay d) {
2088         if (mStableDisplaySize.x <= 0 && mStableDisplaySize.y <= 0) {
2089             DisplayInfo info = d.getDisplayInfoLocked();
2090             setStableDisplaySizeLocked(info.getNaturalWidth(), info.getNaturalHeight());
2091         }
2092     }
2093 
recordTopInsetLocked(@ullable LogicalDisplay d)2094     private void recordTopInsetLocked(@Nullable LogicalDisplay d) {
2095         // We must only persist the inset after boot has completed, otherwise we will end up
2096         // overwriting the persisted value before the masking flag has been loaded from the
2097         // resource overlay.
2098         if (!mSystemReady || d == null) {
2099             return;
2100         }
2101         int topInset = d.getInsets().top;
2102         if (topInset == mDefaultDisplayTopInset) {
2103             return;
2104         }
2105         mDefaultDisplayTopInset = topInset;
2106         SystemProperties.set(PROP_DEFAULT_DISPLAY_TOP_INSET, Integer.toString(topInset));
2107     }
2108 
setStableDisplaySizeLocked(int width, int height)2109     private void setStableDisplaySizeLocked(int width, int height) {
2110         mStableDisplaySize = new Point(width, height);
2111         try {
2112             mPersistentDataStore.setStableDisplaySize(mStableDisplaySize);
2113         } finally {
2114             mPersistentDataStore.saveIfNeeded();
2115         }
2116     }
2117 
2118     @VisibleForTesting
getMinimumBrightnessCurveInternal()2119     Curve getMinimumBrightnessCurveInternal() {
2120         return mMinimumBrightnessCurve;
2121     }
2122 
getPreferredWideGamutColorSpaceIdInternal()2123     int getPreferredWideGamutColorSpaceIdInternal() {
2124         return mWideColorSpace.getId();
2125     }
2126 
getOverlaySupportInternal()2127     OverlayProperties getOverlaySupportInternal() {
2128         return mOverlayProperties;
2129     }
2130 
setUserPreferredDisplayModeInternal(int displayId, Display.Mode mode)2131     void setUserPreferredDisplayModeInternal(int displayId, Display.Mode mode) {
2132         synchronized (mSyncRoot) {
2133             if (mode != null && !isResolutionAndRefreshRateValid(mode)
2134                     && displayId == Display.INVALID_DISPLAY) {
2135                 throw new IllegalArgumentException("width, height and refresh rate of mode should "
2136                         + "be greater than 0 when setting the global user preferred display mode.");
2137             }
2138 
2139             final int resolutionHeight = mode == null ? Display.INVALID_DISPLAY_HEIGHT
2140                     : mode.getPhysicalHeight();
2141             final int resolutionWidth = mode == null ? Display.INVALID_DISPLAY_WIDTH
2142                     : mode.getPhysicalWidth();
2143             final float refreshRate = mode == null ? Display.INVALID_DISPLAY_REFRESH_RATE
2144                     : mode.getRefreshRate();
2145 
2146             storeModeInPersistentDataStoreLocked(
2147                     displayId, resolutionWidth, resolutionHeight, refreshRate);
2148             if (displayId != Display.INVALID_DISPLAY) {
2149                 setUserPreferredModeForDisplayLocked(displayId, mode);
2150             } else {
2151                 mUserPreferredMode = mode;
2152                 storeModeInGlobalSettingsLocked(
2153                         resolutionWidth, resolutionHeight, refreshRate, mode);
2154             }
2155         }
2156     }
2157 
storeModeInPersistentDataStoreLocked(int displayId, int resolutionWidth, int resolutionHeight, float refreshRate)2158     private void storeModeInPersistentDataStoreLocked(int displayId, int resolutionWidth,
2159             int resolutionHeight, float refreshRate) {
2160         DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
2161         if (displayDevice == null) {
2162             return;
2163         }
2164         try {
2165             mPersistentDataStore.setUserPreferredResolution(
2166                     displayDevice, resolutionWidth, resolutionHeight);
2167             mPersistentDataStore.setUserPreferredRefreshRate(displayDevice, refreshRate);
2168         } finally {
2169             mPersistentDataStore.saveIfNeeded();
2170         }
2171     }
2172 
setUserPreferredModeForDisplayLocked(int displayId, Display.Mode mode)2173     private void setUserPreferredModeForDisplayLocked(int displayId, Display.Mode mode) {
2174         DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
2175         if (displayDevice == null) {
2176             return;
2177         }
2178         displayDevice.setUserPreferredDisplayModeLocked(mode);
2179     }
2180 
storeModeInGlobalSettingsLocked( int resolutionWidth, int resolutionHeight, float refreshRate, Display.Mode mode)2181     private void storeModeInGlobalSettingsLocked(
2182             int resolutionWidth, int resolutionHeight, float refreshRate, Display.Mode mode) {
2183         Settings.Global.putFloat(mContext.getContentResolver(),
2184                 Settings.Global.USER_PREFERRED_REFRESH_RATE, refreshRate);
2185         Settings.Global.putInt(mContext.getContentResolver(),
2186                 Settings.Global.USER_PREFERRED_RESOLUTION_HEIGHT, resolutionHeight);
2187         Settings.Global.putInt(mContext.getContentResolver(),
2188                 Settings.Global.USER_PREFERRED_RESOLUTION_WIDTH, resolutionWidth);
2189         mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> {
2190             device.setUserPreferredDisplayModeLocked(mode);
2191         });
2192     }
2193 
2194     @GuardedBy("mSyncRoot")
getEnabledAutoHdrTypesLocked()2195     private int[] getEnabledAutoHdrTypesLocked() {
2196         IntArray autoHdrOutputTypesArray = new IntArray();
2197         for (int type : getSupportedHdrOutputTypesInternal()) {
2198             boolean isDisabled = false;
2199             for (int disabledType : mUserDisabledHdrTypes) {
2200                 if (type == disabledType) {
2201                     isDisabled = true;
2202                     break;
2203                 }
2204             }
2205             if (!isDisabled) {
2206                 autoHdrOutputTypesArray.add(type);
2207             }
2208         }
2209         return autoHdrOutputTypesArray.toArray();
2210     }
2211 
2212     @GuardedBy("mSyncRoot")
hdrConversionIntroducesLatencyLocked()2213     private boolean hdrConversionIntroducesLatencyLocked() {
2214         final int preferredHdrOutputType =
2215                 getHdrConversionModeSettingInternal().getPreferredHdrOutputType();
2216         if (preferredHdrOutputType != Display.HdrCapabilities.HDR_TYPE_INVALID) {
2217             int[] hdrTypesWithLatency = mInjector.getHdrOutputTypesWithLatency();
2218             return ArrayUtils.contains(hdrTypesWithLatency, preferredHdrOutputType);
2219         }
2220         return false;
2221     }
2222 
getUserPreferredDisplayModeInternal(int displayId)2223     Display.Mode getUserPreferredDisplayModeInternal(int displayId) {
2224         synchronized (mSyncRoot) {
2225             if (displayId == Display.INVALID_DISPLAY) {
2226                 return mUserPreferredMode;
2227             }
2228             DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
2229             if (displayDevice == null) {
2230                 return null;
2231             }
2232             return displayDevice.getUserPreferredDisplayModeLocked();
2233         }
2234     }
2235 
getSystemPreferredDisplayModeInternal(int displayId)2236     Display.Mode getSystemPreferredDisplayModeInternal(int displayId) {
2237         synchronized (mSyncRoot) {
2238             final DisplayDevice device = getDeviceForDisplayLocked(displayId);
2239             if (device == null) {
2240                 return null;
2241             }
2242             return device.getSystemPreferredDisplayModeLocked();
2243         }
2244     }
2245 
setHdrConversionModeInternal(HdrConversionMode hdrConversionMode)2246     void setHdrConversionModeInternal(HdrConversionMode hdrConversionMode) {
2247         if (!mInjector.getHdrOutputConversionSupport()) {
2248             return;
2249         }
2250         int[] autoHdrOutputTypes = null;
2251         synchronized (mSyncRoot) {
2252             if (hdrConversionMode.getConversionMode() == HdrConversionMode.HDR_CONVERSION_SYSTEM
2253                     && hdrConversionMode.getPreferredHdrOutputType()
2254                     != Display.HdrCapabilities.HDR_TYPE_INVALID) {
2255                 throw new IllegalArgumentException("preferredHdrOutputType must not be set if"
2256                         + " the conversion mode is HDR_CONVERSION_SYSTEM");
2257             }
2258             mHdrConversionMode = hdrConversionMode;
2259             storeHdrConversionModeLocked(mHdrConversionMode);
2260 
2261             // For auto mode, all supported HDR types are allowed except the ones specifically
2262             // disabled by the user.
2263             if (hdrConversionMode.getConversionMode() == HdrConversionMode.HDR_CONVERSION_SYSTEM) {
2264                 autoHdrOutputTypes = getEnabledAutoHdrTypesLocked();
2265             }
2266 
2267             int conversionMode = hdrConversionMode.getConversionMode();
2268             int preferredHdrType = hdrConversionMode.getPreferredHdrOutputType();
2269             // If the HDR conversion is disabled by an app through WindowManager.LayoutParams, then
2270             // set HDR conversion mode to HDR_CONVERSION_PASSTHROUGH.
2271             if (mOverrideHdrConversionMode == null) {
2272                 // HDR_CONVERSION_FORCE with HDR_TYPE_INVALID is used to represent forcing SDR type.
2273                 // But, internally SDR is selected by using passthrough mode.
2274                 if (conversionMode == HdrConversionMode.HDR_CONVERSION_FORCE
2275                         && preferredHdrType == Display.HdrCapabilities.HDR_TYPE_INVALID) {
2276                     conversionMode = HdrConversionMode.HDR_CONVERSION_PASSTHROUGH;
2277                 }
2278             } else {
2279                 conversionMode = mOverrideHdrConversionMode.getConversionMode();
2280                 preferredHdrType = mOverrideHdrConversionMode.getPreferredHdrOutputType();
2281                 autoHdrOutputTypes = null;
2282             }
2283             mSystemPreferredHdrOutputType = mInjector.setHdrConversionMode(
2284                     conversionMode, preferredHdrType, autoHdrOutputTypes);
2285         }
2286     }
2287 
getHdrConversionModeSettingInternal()2288     HdrConversionMode getHdrConversionModeSettingInternal() {
2289         if (!mInjector.getHdrOutputConversionSupport()) {
2290             return HDR_CONVERSION_MODE_UNSUPPORTED;
2291         }
2292         synchronized (mSyncRoot) {
2293             if (mHdrConversionMode != null) {
2294                 return mHdrConversionMode;
2295             }
2296         }
2297         return new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM);
2298     }
2299 
getHdrConversionModeInternal()2300     HdrConversionMode getHdrConversionModeInternal() {
2301         if (!mInjector.getHdrOutputConversionSupport()) {
2302             return HDR_CONVERSION_MODE_UNSUPPORTED;
2303         }
2304         HdrConversionMode mode;
2305         synchronized (mSyncRoot) {
2306             mode = mOverrideHdrConversionMode != null
2307                     ? mOverrideHdrConversionMode
2308                     : mHdrConversionMode;
2309             if (mode == null
2310                     || mode.getConversionMode() == HdrConversionMode.HDR_CONVERSION_SYSTEM) {
2311                 return new HdrConversionMode(
2312                         HdrConversionMode.HDR_CONVERSION_SYSTEM, mSystemPreferredHdrOutputType);
2313             }
2314         }
2315         return mode;
2316     }
2317 
getSupportedHdrOutputTypesInternal()2318     private @Display.HdrCapabilities.HdrType int[] getSupportedHdrOutputTypesInternal() {
2319         if (mSupportedHdrOutputType == null) {
2320             mSupportedHdrOutputType = mInjector.getSupportedHdrOutputTypes();
2321         }
2322         return mSupportedHdrOutputType;
2323     }
2324 
setShouldAlwaysRespectAppRequestedModeInternal(boolean enabled)2325     void setShouldAlwaysRespectAppRequestedModeInternal(boolean enabled) {
2326         mDisplayModeDirector.setShouldAlwaysRespectAppRequestedMode(enabled);
2327     }
2328 
shouldAlwaysRespectAppRequestedModeInternal()2329     boolean shouldAlwaysRespectAppRequestedModeInternal() {
2330         return mDisplayModeDirector.shouldAlwaysRespectAppRequestedMode();
2331     }
2332 
setRefreshRateSwitchingTypeInternal(@isplayManager.SwitchingType int newValue)2333     void setRefreshRateSwitchingTypeInternal(@DisplayManager.SwitchingType int newValue) {
2334         mDisplayModeDirector.setModeSwitchingType(newValue);
2335     }
2336 
2337     @DisplayManager.SwitchingType
getRefreshRateSwitchingTypeInternal()2338     int getRefreshRateSwitchingTypeInternal() {
2339         return mDisplayModeDirector.getModeSwitchingType();
2340     }
2341 
getDisplayDecorationSupportInternal(int displayId)2342     private DisplayDecorationSupport getDisplayDecorationSupportInternal(int displayId) {
2343         final IBinder displayToken = getDisplayToken(displayId);
2344         if (null == displayToken) {
2345             return null;
2346         }
2347         return SurfaceControl.getDisplayDecorationSupport(displayToken);
2348     }
2349 
setBrightnessConfigurationForDisplayInternal( @ullable BrightnessConfiguration c, String uniqueId, @UserIdInt int userId, String packageName)2350     private void setBrightnessConfigurationForDisplayInternal(
2351             @Nullable BrightnessConfiguration c, String uniqueId, @UserIdInt int userId,
2352             String packageName) {
2353         validateBrightnessConfiguration(c);
2354         final int userSerial = getUserManager().getUserSerialNumber(userId);
2355         synchronized (mSyncRoot) {
2356             try {
2357                 DisplayDevice displayDevice = mDisplayDeviceRepo.getByUniqueIdLocked(uniqueId);
2358                 if (displayDevice == null) {
2359                     return;
2360                 }
2361                 if (mLogicalDisplayMapper.getDisplayLocked(displayDevice) != null
2362                         && mLogicalDisplayMapper.getDisplayLocked(displayDevice)
2363                         .getDisplayInfoLocked().type == Display.TYPE_INTERNAL && c != null) {
2364                     FrameworkStatsLog.write(FrameworkStatsLog.BRIGHTNESS_CONFIGURATION_UPDATED,
2365                                 c.getCurve().first,
2366                                 c.getCurve().second,
2367                                 // should not be logged for virtual displays
2368                                 uniqueId);
2369                 }
2370                 mPersistentDataStore.setBrightnessConfigurationForDisplayLocked(c, displayDevice,
2371                         userSerial, packageName);
2372             } finally {
2373                 mPersistentDataStore.saveIfNeeded();
2374             }
2375             if (userId != mCurrentUserId) {
2376                 return;
2377             }
2378             DisplayPowerControllerInterface dpc = getDpcFromUniqueIdLocked(uniqueId);
2379             if (dpc != null) {
2380                 dpc.setBrightnessConfiguration(c, /* shouldResetShortTermModel= */ true);
2381             }
2382         }
2383     }
2384 
getDpcFromUniqueIdLocked(String uniqueId)2385     private DisplayPowerControllerInterface getDpcFromUniqueIdLocked(String uniqueId) {
2386         final DisplayDevice displayDevice = mDisplayDeviceRepo.getByUniqueIdLocked(uniqueId);
2387         final LogicalDisplay logicalDisplay = mLogicalDisplayMapper.getDisplayLocked(displayDevice);
2388         if (logicalDisplay != null) {
2389             final int displayId = logicalDisplay.getDisplayIdLocked();
2390             return mDisplayPowerControllers.get(displayId);
2391         }
2392         return null;
2393     }
2394 
2395     @VisibleForTesting
validateBrightnessConfiguration(BrightnessConfiguration config)2396     void validateBrightnessConfiguration(BrightnessConfiguration config) {
2397         if (config == null) {
2398             return;
2399         }
2400         if (isBrightnessConfigurationTooDark(config)) {
2401             throw new IllegalArgumentException("brightness curve is too dark");
2402         }
2403     }
2404 
isBrightnessConfigurationTooDark(BrightnessConfiguration config)2405     private boolean isBrightnessConfigurationTooDark(BrightnessConfiguration config) {
2406         Pair<float[], float[]> curve = config.getCurve();
2407         float[] lux = curve.first;
2408         float[] nits = curve.second;
2409         for (int i = 0; i < lux.length; i++) {
2410             if (nits[i] < mMinimumBrightnessSpline.interpolate(lux[i])) {
2411                 return true;
2412             }
2413         }
2414         return false;
2415     }
2416 
loadBrightnessConfigurations()2417     private void loadBrightnessConfigurations() {
2418         int userSerial = getUserManager().getUserSerialNumber(mContext.getUserId());
2419         synchronized (mSyncRoot) {
2420             mLogicalDisplayMapper.forEachLocked((logicalDisplay) -> {
2421                 final String uniqueId =
2422                         logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
2423                 final BrightnessConfiguration config =
2424                         getBrightnessConfigForDisplayWithPdsFallbackLocked(uniqueId, userSerial);
2425                 if (config != null) {
2426                     final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(
2427                             logicalDisplay.getDisplayIdLocked());
2428                     if (dpc != null) {
2429                         dpc.setBrightnessConfiguration(config,
2430                                 /* shouldResetShortTermModel= */ false);
2431                     }
2432                 }
2433             });
2434         }
2435     }
2436 
performTraversalLocked(SurfaceControl.Transaction t)2437     private void performTraversalLocked(SurfaceControl.Transaction t) {
2438         // Clear all viewports before configuring displays so that we can keep
2439         // track of which ones we have configured.
2440         clearViewportsLocked();
2441 
2442         // Configure each display device.
2443         mLogicalDisplayMapper.forEachLocked((LogicalDisplay display) -> {
2444             final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
2445             if (device != null) {
2446                 configureDisplayLocked(t, device);
2447                 device.performTraversalLocked(t);
2448             }
2449         });
2450 
2451         // Tell the input system about these new viewports.
2452         if (mInputManagerInternal != null) {
2453             mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
2454         }
2455     }
2456 
setDisplayPropertiesInternal(int displayId, boolean hasContent, float requestedRefreshRate, int requestedModeId, float requestedMinRefreshRate, float requestedMaxRefreshRate, boolean preferMinimalPostProcessing, boolean disableHdrConversion, boolean inTraversal)2457     void setDisplayPropertiesInternal(int displayId, boolean hasContent,
2458             float requestedRefreshRate, int requestedModeId, float requestedMinRefreshRate,
2459             float requestedMaxRefreshRate, boolean preferMinimalPostProcessing,
2460             boolean disableHdrConversion, boolean inTraversal) {
2461         synchronized (mSyncRoot) {
2462             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
2463             if (display == null) {
2464                 return;
2465             }
2466 
2467             boolean shouldScheduleTraversal = false;
2468 
2469             if (display.hasContentLocked() != hasContent) {
2470                 if (DEBUG) {
2471                     Slog.d(TAG, "Display " + displayId + " hasContent flag changed: "
2472                             + "hasContent=" + hasContent + ", inTraversal=" + inTraversal);
2473                 }
2474 
2475                 display.setHasContentLocked(hasContent);
2476                 shouldScheduleTraversal = true;
2477             }
2478             if (requestedModeId == 0 && requestedRefreshRate != 0) {
2479                 // Scan supported modes returned by display.getInfo() to find a mode with the same
2480                 // size as the default display mode but with the specified refresh rate instead.
2481                 Display.Mode mode = display.getDisplayInfoLocked().findDefaultModeByRefreshRate(
2482                         requestedRefreshRate);
2483                 if (mode != null) {
2484                     requestedModeId = mode.getModeId();
2485                 } else {
2486                     Slog.e(TAG, "Couldn't find a mode for the requestedRefreshRate: "
2487                             + requestedRefreshRate + " on Display: " + displayId);
2488                 }
2489             }
2490             mDisplayModeDirector.getAppRequestObserver().setAppRequest(
2491                     displayId, requestedModeId, requestedMinRefreshRate, requestedMaxRefreshRate);
2492 
2493             // TODO(b/202378408) set minimal post-processing only if it's supported once we have a
2494             // separate API for disabling on-device processing.
2495             boolean mppRequest = isMinimalPostProcessingAllowed() && preferMinimalPostProcessing;
2496             boolean disableHdrConversionForLatency = false;
2497 
2498             if (display.getRequestedMinimalPostProcessingLocked() != mppRequest) {
2499                 display.setRequestedMinimalPostProcessingLocked(mppRequest);
2500                 shouldScheduleTraversal = true;
2501                 // If HDR conversion introduces latency, disable that in case minimal
2502                 // post-processing is requested
2503                 if (mppRequest) {
2504                     disableHdrConversionForLatency = hdrConversionIntroducesLatencyLocked();
2505                 }
2506             }
2507 
2508             if (shouldScheduleTraversal) {
2509                 scheduleTraversalLocked(inTraversal);
2510             }
2511 
2512             if (mHdrConversionMode == null) {
2513                 return;
2514             }
2515             // HDR conversion is disabled in two cases:
2516             // - HDR conversion introduces latency and minimal post-processing is requested
2517             // - app requests to disable HDR conversion
2518             if (mOverrideHdrConversionMode == null && (disableHdrConversion
2519                     || disableHdrConversionForLatency)) {
2520                 mOverrideHdrConversionMode =
2521                             new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_PASSTHROUGH);
2522                 setHdrConversionModeInternal(mHdrConversionMode);
2523                 handleLogicalDisplayChangedLocked(display);
2524             } else if (mOverrideHdrConversionMode != null && !disableHdrConversion
2525                     && !disableHdrConversionForLatency) {
2526                 mOverrideHdrConversionMode = null;
2527                 setHdrConversionModeInternal(mHdrConversionMode);
2528                 handleLogicalDisplayChangedLocked(display);
2529             }
2530         }
2531     }
2532 
setDisplayOffsetsInternal(int displayId, int x, int y)2533     private void setDisplayOffsetsInternal(int displayId, int x, int y) {
2534         synchronized (mSyncRoot) {
2535             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
2536             if (display == null) {
2537                 return;
2538             }
2539             if (display.getDisplayOffsetXLocked() != x
2540                     || display.getDisplayOffsetYLocked() != y) {
2541                 if (DEBUG) {
2542                     Slog.d(TAG, "Display " + displayId + " burn-in offset set to ("
2543                             + x + ", " + y + ")");
2544                 }
2545                 display.setDisplayOffsetsLocked(x, y);
2546                 scheduleTraversalLocked(false);
2547             }
2548         }
2549     }
2550 
setDisplayScalingDisabledInternal(int displayId, boolean disable)2551     private void setDisplayScalingDisabledInternal(int displayId, boolean disable) {
2552         synchronized (mSyncRoot) {
2553             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
2554             if (display == null) {
2555                 return;
2556             }
2557             if (display.isDisplayScalingDisabled() != disable) {
2558                 if (DEBUG) {
2559                     Slog.d(TAG, "Display " + displayId + " content scaling disabled = " + disable);
2560                 }
2561                 display.setDisplayScalingDisabledLocked(disable);
2562                 scheduleTraversalLocked(false);
2563             }
2564         }
2565     }
2566 
2567     // Updates the lists of UIDs that are present on displays.
setDisplayAccessUIDsInternal(SparseArray<IntArray> newDisplayAccessUIDs)2568     private void setDisplayAccessUIDsInternal(SparseArray<IntArray> newDisplayAccessUIDs) {
2569         synchronized (mSyncRoot) {
2570             mDisplayAccessUIDs.clear();
2571             for (int i = newDisplayAccessUIDs.size() - 1; i >= 0; i--) {
2572                 mDisplayAccessUIDs.append(newDisplayAccessUIDs.keyAt(i),
2573                         newDisplayAccessUIDs.valueAt(i));
2574             }
2575         }
2576     }
2577 
2578     // Checks if provided UID's content is present on the display and UID has access to it.
isUidPresentOnDisplayInternal(int uid, int displayId)2579     private boolean isUidPresentOnDisplayInternal(int uid, int displayId) {
2580         synchronized (mSyncRoot) {
2581             final IntArray displayUIDs = mDisplayAccessUIDs.get(displayId);
2582             return displayUIDs != null && displayUIDs.indexOf(uid) != -1;
2583         }
2584     }
2585 
2586     @Nullable
getDisplayToken(int displayId)2587     private IBinder getDisplayToken(int displayId) {
2588         synchronized (mSyncRoot) {
2589             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
2590             if (display != null) {
2591                 final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
2592                 if (device != null) {
2593                     return device.getDisplayTokenLocked();
2594                 }
2595             }
2596         }
2597 
2598         return null;
2599     }
2600 
systemScreenshotInternal(int displayId)2601     private ScreenCapture.ScreenshotHardwareBuffer systemScreenshotInternal(int displayId) {
2602         final ScreenCapture.DisplayCaptureArgs captureArgs;
2603         synchronized (mSyncRoot) {
2604             final IBinder token = getDisplayToken(displayId);
2605             if (token == null) {
2606                 return null;
2607             }
2608             final LogicalDisplay logicalDisplay = mLogicalDisplayMapper.getDisplayLocked(displayId);
2609             if (logicalDisplay == null) {
2610                 return null;
2611             }
2612 
2613             final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked();
2614             captureArgs = new ScreenCapture.DisplayCaptureArgs.Builder(token)
2615                     .setSize(displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight())
2616                     .setCaptureSecureLayers(true)
2617                     .setAllowProtected(true)
2618                     .build();
2619         }
2620         return ScreenCapture.captureDisplay(captureArgs);
2621     }
2622 
userScreenshotInternal(int displayId)2623     private ScreenCapture.ScreenshotHardwareBuffer userScreenshotInternal(int displayId) {
2624         synchronized (mSyncRoot) {
2625             final IBinder token = getDisplayToken(displayId);
2626             if (token == null) {
2627                 return null;
2628             }
2629 
2630             final ScreenCapture.DisplayCaptureArgs captureArgs =
2631                     new ScreenCapture.DisplayCaptureArgs.Builder(token)
2632                             .build();
2633             return ScreenCapture.captureDisplay(captureArgs);
2634         }
2635     }
2636 
2637     @VisibleForTesting
getDisplayedContentSamplingAttributesInternal( int displayId)2638     DisplayedContentSamplingAttributes getDisplayedContentSamplingAttributesInternal(
2639             int displayId) {
2640         final IBinder token = getDisplayToken(displayId);
2641         if (token == null) {
2642             return null;
2643         }
2644         return SurfaceControl.getDisplayedContentSamplingAttributes(token);
2645     }
2646 
2647     @VisibleForTesting
setDisplayedContentSamplingEnabledInternal( int displayId, boolean enable, int componentMask, int maxFrames)2648     boolean setDisplayedContentSamplingEnabledInternal(
2649             int displayId, boolean enable, int componentMask, int maxFrames) {
2650         final IBinder token = getDisplayToken(displayId);
2651         if (token == null) {
2652             return false;
2653         }
2654         return SurfaceControl.setDisplayedContentSamplingEnabled(
2655                 token, enable, componentMask, maxFrames);
2656     }
2657 
2658     @VisibleForTesting
getDisplayedContentSampleInternal(int displayId, long maxFrames, long timestamp)2659     DisplayedContentSample getDisplayedContentSampleInternal(int displayId,
2660             long maxFrames, long timestamp) {
2661         final IBinder token = getDisplayToken(displayId);
2662         if (token == null) {
2663             return null;
2664         }
2665         return SurfaceControl.getDisplayedContentSample(token, maxFrames, timestamp);
2666     }
2667 
resetBrightnessConfigurations()2668     void resetBrightnessConfigurations() {
2669         mPersistentDataStore.setBrightnessConfigurationForUser(null, mContext.getUserId(),
2670                 mContext.getPackageName());
2671         mLogicalDisplayMapper.forEachLocked((logicalDisplay -> {
2672             if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
2673                 return;
2674             }
2675             final String uniqueId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
2676             setBrightnessConfigurationForDisplayInternal(null, uniqueId, mContext.getUserId(),
2677                     mContext.getPackageName());
2678         }));
2679     }
2680 
setAutoBrightnessLoggingEnabled(boolean enabled)2681     void setAutoBrightnessLoggingEnabled(boolean enabled) {
2682         synchronized (mSyncRoot) {
2683             final DisplayPowerControllerInterface displayPowerController =
2684                     mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY);
2685             if (displayPowerController != null) {
2686                 displayPowerController.setAutoBrightnessLoggingEnabled(enabled);
2687             }
2688         }
2689     }
2690 
setDisplayWhiteBalanceLoggingEnabled(boolean enabled)2691     void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) {
2692         synchronized (mSyncRoot) {
2693             final DisplayPowerControllerInterface displayPowerController =
2694                     mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY);
2695             if (displayPowerController != null) {
2696                 displayPowerController.setDisplayWhiteBalanceLoggingEnabled(enabled);
2697             }
2698         }
2699     }
2700 
setDisplayModeDirectorLoggingEnabled(boolean enabled)2701     void setDisplayModeDirectorLoggingEnabled(boolean enabled) {
2702         synchronized (mSyncRoot) {
2703             mDisplayModeDirector.setLoggingEnabled(enabled);
2704         }
2705     }
2706 
getActiveDisplayModeAtStart(int displayId)2707     Display.Mode getActiveDisplayModeAtStart(int displayId) {
2708         synchronized (mSyncRoot) {
2709             final DisplayDevice device = getDeviceForDisplayLocked(displayId);
2710             if (device == null) {
2711                 return null;
2712             }
2713             return device.getActiveDisplayModeAtStartLocked();
2714         }
2715     }
2716 
setAmbientColorTemperatureOverride(float cct)2717     void setAmbientColorTemperatureOverride(float cct) {
2718         synchronized (mSyncRoot) {
2719             final DisplayPowerControllerInterface displayPowerController =
2720                     mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY);
2721             if (displayPowerController != null) {
2722                 displayPowerController.setAmbientColorTemperatureOverride(cct);
2723             }
2724         }
2725     }
2726 
setDockedAndIdleEnabled(boolean enabled, int displayId)2727     void setDockedAndIdleEnabled(boolean enabled, int displayId) {
2728         synchronized (mSyncRoot) {
2729             final DisplayPowerControllerInterface displayPowerController =
2730                     mDisplayPowerControllers.get(displayId);
2731             if (displayPowerController != null) {
2732                 displayPowerController.setAutomaticScreenBrightnessMode(enabled);
2733             }
2734         }
2735     }
2736 
clearViewportsLocked()2737     private void clearViewportsLocked() {
2738         mViewports.clear();
2739     }
2740 
getViewportType(DisplayDeviceInfo info)2741     private Optional<Integer> getViewportType(DisplayDeviceInfo info) {
2742         // Get the corresponding viewport type.
2743         switch (info.touch) {
2744             case DisplayDeviceInfo.TOUCH_INTERNAL:
2745                 return Optional.of(VIEWPORT_INTERNAL);
2746             case DisplayDeviceInfo.TOUCH_EXTERNAL:
2747                 return Optional.of(VIEWPORT_EXTERNAL);
2748             case DisplayDeviceInfo.TOUCH_VIRTUAL:
2749                 if (!TextUtils.isEmpty(info.uniqueId)) {
2750                     return Optional.of(VIEWPORT_VIRTUAL);
2751                 }
2752                 // fallthrough
2753             default:
2754                 if (DEBUG) {
2755                     Slog.w(TAG, "Display " + info + " does not support input device matching.");
2756                 }
2757         }
2758         return Optional.empty();
2759     }
2760 
configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device)2761     private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) {
2762         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
2763 
2764         // Find the logical display that the display device is showing.
2765         // Certain displays only ever show their own content.
2766         LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
2767 
2768         // Apply the logical display configuration to the display device.
2769         if (display == null) {
2770             // TODO: no logical display for the device, blank it
2771             Slog.w(TAG, "Missing logical display to use for physical display device: "
2772                     + device.getDisplayDeviceInfoLocked());
2773             return;
2774         }
2775         display.configureDisplayLocked(t, device, info.state == Display.STATE_OFF);
2776         final Optional<Integer> viewportType = getViewportType(info);
2777         if (viewportType.isPresent()) {
2778             populateViewportLocked(viewportType.get(), display.getDisplayIdLocked(), device, info);
2779         }
2780     }
2781 
2782     /**
2783      * Get internal or external viewport. Create it if does not currently exist.
2784      * @param viewportType - either INTERNAL or EXTERNAL
2785      * @return the viewport with the requested type
2786      */
getViewportLocked(int viewportType, String uniqueId)2787     private DisplayViewport getViewportLocked(int viewportType, String uniqueId) {
2788         if (viewportType != VIEWPORT_INTERNAL && viewportType != VIEWPORT_EXTERNAL
2789                 && viewportType != VIEWPORT_VIRTUAL) {
2790             Slog.wtf(TAG, "Cannot call getViewportByTypeLocked for type "
2791                     + DisplayViewport.typeToString(viewportType));
2792             return null;
2793         }
2794 
2795         DisplayViewport viewport;
2796         final int count = mViewports.size();
2797         for (int i = 0; i < count; i++) {
2798             viewport = mViewports.get(i);
2799             if (viewport.type == viewportType && uniqueId.equals(viewport.uniqueId)) {
2800                 return viewport;
2801             }
2802         }
2803 
2804         // Creates the viewport if none exists.
2805         viewport = new DisplayViewport();
2806         viewport.type = viewportType;
2807         viewport.uniqueId = uniqueId;
2808         mViewports.add(viewport);
2809         return viewport;
2810     }
2811 
populateViewportLocked(int viewportType, int displayId, DisplayDevice device, DisplayDeviceInfo info)2812     private void populateViewportLocked(int viewportType, int displayId, DisplayDevice device,
2813             DisplayDeviceInfo info) {
2814         final DisplayViewport viewport = getViewportLocked(viewportType, info.uniqueId);
2815         device.populateViewportLocked(viewport);
2816         viewport.valid = true;
2817         viewport.displayId = displayId;
2818         viewport.isActive = Display.isActiveState(info.state);
2819     }
2820 
updateViewportPowerStateLocked(LogicalDisplay display)2821     private void updateViewportPowerStateLocked(LogicalDisplay display) {
2822         final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
2823         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
2824         final Optional<Integer> viewportType = getViewportType(info);
2825         if (viewportType.isPresent()) {
2826             for (DisplayViewport d : mViewports) {
2827                 if (d.type == viewportType.get() && info.uniqueId.equals(d.uniqueId)) {
2828                     // Update display view port power state
2829                     d.isActive = Display.isActiveState(info.state);
2830                 }
2831             }
2832             if (mInputManagerInternal != null) {
2833                 mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
2834             }
2835         }
2836     }
2837 
sendDisplayEventLocked(@onNull LogicalDisplay display, @DisplayEvent int event)2838     private void sendDisplayEventLocked(@NonNull LogicalDisplay display, @DisplayEvent int event) {
2839         // Only send updates outside of DisplayManagerService for enabled displays
2840         if (display.isEnabledLocked()) {
2841             int displayId = display.getDisplayIdLocked();
2842             Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
2843             mHandler.sendMessage(msg);
2844         }
2845     }
2846 
sendDisplayGroupEvent(int groupId, int event)2847     private void sendDisplayGroupEvent(int groupId, int event) {
2848         Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_GROUP_EVENT, groupId, event);
2849         mHandler.sendMessage(msg);
2850     }
2851 
sendDisplayEventFrameRateOverrideLocked(int displayId)2852     private void sendDisplayEventFrameRateOverrideLocked(int displayId) {
2853         Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
2854                 displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
2855         mHandler.sendMessage(msg);
2856     }
2857 
2858     // Requests that performTraversals be called at a
2859     // later time to apply changes to surfaces and displays.
scheduleTraversalLocked(boolean inTraversal)2860     private void scheduleTraversalLocked(boolean inTraversal) {
2861         if (!mPendingTraversal && mWindowManagerInternal != null) {
2862             mPendingTraversal = true;
2863             if (!inTraversal) {
2864                 mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
2865             }
2866         }
2867     }
2868 
2869     // Check if the target app is in cached mode
isUidCached(int uid)2870     private boolean isUidCached(int uid) {
2871         // Only query procState and importance for Android apps, which have UIDs starting
2872         // from FIRST_APPLICATION_UID. .
2873         //
2874         // Other processes with UID < FIRST_APPLICATION_UID can also register to DMS for
2875         // display events. E.g. Android Studio executes a screen sharing process to provide
2876         // display mirroring functionality. That process inherits the UID of adb. Depending
2877         // on adb mode, it can be shell (2000) or root (0). Those processes are not Android
2878         // apps and not managed by AMS. Treat them as non-cached so never ignore or defer
2879         // display events to them.
2880         if (mActivityManagerInternal == null || uid < FIRST_APPLICATION_UID) {
2881             return false;
2882         }
2883         int procState = mActivityManagerInternal.getUidProcessState(uid);
2884         int importance = ActivityManager.RunningAppProcessInfo.procStateToImportance(procState);
2885         return importance >= IMPORTANCE_CACHED;
2886     }
2887 
2888     // Runs on Handler thread.
2889     // Delivers display event notifications to callbacks.
deliverDisplayEvent(int displayId, ArraySet<Integer> uids, @DisplayEvent int event)2890     private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids,
2891             @DisplayEvent int event) {
2892         if (DEBUG || mExtraDisplayEventLogging) {
2893             Slog.d(TAG, "Delivering display event: displayId="
2894                     + displayId + ", event=" + event
2895                     + (uids != null ? ", uids=" + uids : ""));
2896         }
2897 
2898         // Grab the lock and copy the callbacks.
2899         final int count;
2900         synchronized (mSyncRoot) {
2901             count = mCallbacks.size();
2902             mTempCallbacks.clear();
2903             for (int i = 0; i < count; i++) {
2904                 if (uids == null || uids.contains(mCallbacks.valueAt(i).mUid)) {
2905                     mTempCallbacks.add(mCallbacks.valueAt(i));
2906                 }
2907             }
2908         }
2909 
2910         // After releasing the lock, send the notifications out.
2911         for (int i = 0; i < mTempCallbacks.size(); i++) {
2912             CallbackRecord callbackRecord = mTempCallbacks.get(i);
2913             final int uid = callbackRecord.mUid;
2914             if (isUidCached(uid)) {
2915                 // For cached apps, save the pending event until it becomes non-cached
2916                 synchronized (mPendingCallbackSelfLocked) {
2917                     PendingCallback pendingCallback = mPendingCallbackSelfLocked.get(uid);
2918                     if (pendingCallback == null) {
2919                         mPendingCallbackSelfLocked.put(uid,
2920                                 new PendingCallback(callbackRecord, displayId, event));
2921                     } else {
2922                         pendingCallback.addDisplayEvent(displayId, event);
2923                     }
2924                 }
2925             } else {
2926                 callbackRecord.notifyDisplayEventAsync(displayId, event);
2927             }
2928         }
2929         mTempCallbacks.clear();
2930     }
2931 
2932     // Runs on Handler thread.
2933     // Delivers display group event notifications to callbacks.
deliverDisplayGroupEvent(int groupId, int event)2934     private void deliverDisplayGroupEvent(int groupId, int event) {
2935         if (DEBUG) {
2936             Slog.d(TAG, "Delivering display group event: groupId=" + groupId + ", event="
2937                     + event);
2938         }
2939 
2940         switch (event) {
2941             case LogicalDisplayMapper.DISPLAY_GROUP_EVENT_ADDED:
2942                 for (DisplayGroupListener listener : mDisplayGroupListeners) {
2943                     listener.onDisplayGroupAdded(groupId);
2944                 }
2945                 break;
2946 
2947             case LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED:
2948                 for (DisplayGroupListener listener : mDisplayGroupListeners) {
2949                     listener.onDisplayGroupChanged(groupId);
2950                 }
2951                 break;
2952 
2953             case LogicalDisplayMapper.DISPLAY_GROUP_EVENT_REMOVED:
2954                 for (DisplayGroupListener listener : mDisplayGroupListeners) {
2955                     listener.onDisplayGroupRemoved(groupId);
2956                 }
2957                 break;
2958         }
2959     }
2960 
getProjectionService()2961     private IMediaProjectionManager getProjectionService() {
2962         if (mProjectionService == null) {
2963             mProjectionService = mInjector.getProjectionService();
2964         }
2965         return mProjectionService;
2966     }
2967 
getUserManager()2968     private UserManager getUserManager() {
2969         return mContext.getSystemService(UserManager.class);
2970     }
2971 
dumpInternal(PrintWriter pw)2972     private void dumpInternal(PrintWriter pw) {
2973         pw.println("DISPLAY MANAGER (dumpsys display)");
2974         BrightnessTracker brightnessTrackerLocal;
2975 
2976         synchronized (mSyncRoot) {
2977             brightnessTrackerLocal = mBrightnessTracker;
2978 
2979             pw.println("  mSafeMode=" + mSafeMode);
2980             pw.println("  mPendingTraversal=" + mPendingTraversal);
2981             pw.println("  mViewports=" + mViewports);
2982             pw.println("  mDefaultDisplayDefaultColorMode=" + mDefaultDisplayDefaultColorMode);
2983             pw.println("  mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
2984             pw.println("  mStableDisplaySize=" + mStableDisplaySize);
2985             pw.println("  mMinimumBrightnessCurve=" + mMinimumBrightnessCurve);
2986 
2987             if (mUserPreferredMode != null) {
2988                 pw.println(" mUserPreferredMode=" + mUserPreferredMode);
2989             }
2990 
2991             pw.println();
2992             if (!mAreUserDisabledHdrTypesAllowed) {
2993                 pw.println("  mUserDisabledHdrTypes: size=" + mUserDisabledHdrTypes.length);
2994                 for (int type : mUserDisabledHdrTypes) {
2995                     pw.println("  " + type);
2996                 }
2997             }
2998 
2999             if (mHdrConversionMode != null) {
3000                 pw.println("  mHdrConversionMode=" + mHdrConversionMode);
3001             }
3002 
3003             pw.println();
3004             final int displayStateCount = mDisplayStates.size();
3005             pw.println("Display States: size=" + displayStateCount);
3006             for (int i = 0; i < displayStateCount; i++) {
3007                 final int displayId = mDisplayStates.keyAt(i);
3008                 final int displayState = mDisplayStates.valueAt(i);
3009                 final BrightnessPair brightnessPair = mDisplayBrightnesses.valueAt(i);
3010                 pw.println("  Display Id=" + displayId);
3011                 pw.println("  Display State=" + Display.stateToString(displayState));
3012                 pw.println("  Display Brightness=" + brightnessPair.brightness);
3013                 pw.println("  Display SdrBrightness=" + brightnessPair.sdrBrightness);
3014             }
3015 
3016             IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
3017             ipw.increaseIndent();
3018 
3019             pw.println();
3020             pw.println("Display Adapters: size=" + mDisplayAdapters.size());
3021             for (DisplayAdapter adapter : mDisplayAdapters) {
3022                 pw.println("  " + adapter.getName());
3023                 adapter.dumpLocked(ipw);
3024             }
3025 
3026             pw.println();
3027             pw.println("Display Devices: size=" + mDisplayDeviceRepo.sizeLocked());
3028             mDisplayDeviceRepo.forEachLocked(device -> {
3029                 pw.println("  " + device.getDisplayDeviceInfoLocked());
3030                 device.dumpLocked(ipw);
3031             });
3032 
3033             pw.println();
3034             mLogicalDisplayMapper.dumpLocked(pw);
3035 
3036             final int callbackCount = mCallbacks.size();
3037             pw.println();
3038             pw.println("Callbacks: size=" + callbackCount);
3039             for (int i = 0; i < callbackCount; i++) {
3040                 CallbackRecord callback = mCallbacks.valueAt(i);
3041                 pw.println("  " + i + ": mPid=" + callback.mPid
3042                         + ", mWifiDisplayScanRequested=" + callback.mWifiDisplayScanRequested);
3043             }
3044 
3045             final int displayPowerControllerCount = mDisplayPowerControllers.size();
3046             pw.println();
3047             pw.println("Display Power Controllers: size=" + displayPowerControllerCount);
3048             for (int i = 0; i < displayPowerControllerCount; i++) {
3049                 mDisplayPowerControllers.valueAt(i).dump(pw);
3050             }
3051             pw.println();
3052             mPersistentDataStore.dump(pw);
3053 
3054             final int displayWindowPolicyControllerCount = mDisplayWindowPolicyControllers.size();
3055             pw.println();
3056             pw.println("Display Window Policy Controllers: size="
3057                     + displayWindowPolicyControllerCount);
3058             for (int i = 0; i < displayWindowPolicyControllerCount; i++) {
3059                 pw.print("Display " + mDisplayWindowPolicyControllers.keyAt(i) + ":");
3060                 mDisplayWindowPolicyControllers.valueAt(i).second.dump("  ", pw);
3061             }
3062         }
3063         if (brightnessTrackerLocal != null) {
3064             pw.println();
3065             brightnessTrackerLocal.dump(pw);
3066         }
3067         pw.println();
3068         mDisplayModeDirector.dump(pw);
3069         mBrightnessSynchronizer.dump(pw);
3070         if (mSmallAreaDetectionController != null) {
3071             mSmallAreaDetectionController.dump(pw);
3072         }
3073     }
3074 
getFloatArray(TypedArray array)3075     private static float[] getFloatArray(TypedArray array) {
3076         int length = array.length();
3077         float[] floatArray = new float[length];
3078         for (int i = 0; i < length; i++) {
3079             floatArray[i] = array.getFloat(i, Float.NaN);
3080         }
3081         array.recycle();
3082         return floatArray;
3083     }
3084 
isResolutionAndRefreshRateValid(Display.Mode mode)3085     private static boolean isResolutionAndRefreshRateValid(Display.Mode mode) {
3086         return mode.getPhysicalWidth() > 0 && mode.getPhysicalHeight() > 0
3087                 && mode.getRefreshRate() > 0.0f;
3088     }
3089 
3090     /**
3091      * This is the object that everything in the display manager locks on.
3092      * We make it an inner class within the {@link DisplayManagerService} to so that it is
3093      * clear that the object belongs to the display manager service and that it is
3094      * a unique object with a special purpose.
3095      */
3096     public static final class SyncRoot {
3097     }
3098 
3099     @VisibleForTesting
3100     static class Injector {
getVirtualDisplayAdapter(SyncRoot syncRoot, Context context, Handler handler, DisplayAdapter.Listener displayAdapterListener)3101         VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
3102                 Handler handler, DisplayAdapter.Listener displayAdapterListener) {
3103             return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener);
3104         }
3105 
getLocalDisplayAdapter(SyncRoot syncRoot, Context context, Handler handler, DisplayAdapter.Listener displayAdapterListener)3106         LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context,
3107                 Handler handler, DisplayAdapter.Listener displayAdapterListener) {
3108             return new LocalDisplayAdapter(syncRoot, context, handler, displayAdapterListener);
3109         }
3110 
getDefaultDisplayDelayTimeout()3111         long getDefaultDisplayDelayTimeout() {
3112             return WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
3113         }
3114 
setHdrConversionMode(int conversionMode, int preferredHdrOutputType, int[] autoHdrTypes)3115         int setHdrConversionMode(int conversionMode, int preferredHdrOutputType,
3116                 int[] autoHdrTypes) {
3117             return DisplayControl.setHdrConversionMode(conversionMode, preferredHdrOutputType,
3118                     autoHdrTypes);
3119         }
3120 
getSupportedHdrOutputTypes()3121         int[] getSupportedHdrOutputTypes() {
3122             return DisplayControl.getSupportedHdrOutputTypes();
3123         }
3124 
getHdrOutputTypesWithLatency()3125         int[] getHdrOutputTypesWithLatency() {
3126             return DisplayControl.getHdrOutputTypesWithLatency();
3127         }
3128 
getHdrOutputConversionSupport()3129         boolean getHdrOutputConversionSupport() {
3130             return DisplayControl.getHdrOutputConversionSupport();
3131         }
3132 
getProjectionService()3133         IMediaProjectionManager getProjectionService() {
3134             IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
3135             return  IMediaProjectionManager.Stub.asInterface(b);
3136         }
3137     }
3138 
3139     @VisibleForTesting
getDisplayDeviceInfoInternal(int displayId)3140     DisplayDeviceInfo getDisplayDeviceInfoInternal(int displayId) {
3141         synchronized (mSyncRoot) {
3142             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
3143             if (display != null) {
3144                 final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
3145                 return displayDevice.getDisplayDeviceInfoLocked();
3146             }
3147             return null;
3148         }
3149     }
3150 
3151     @VisibleForTesting
getVirtualDisplaySurfaceInternal(IBinder appToken)3152     Surface getVirtualDisplaySurfaceInternal(IBinder appToken) {
3153         synchronized (mSyncRoot) {
3154             if (mVirtualDisplayAdapter == null) {
3155                 return null;
3156             }
3157             return mVirtualDisplayAdapter.getVirtualDisplaySurfaceLocked(appToken);
3158         }
3159     }
3160 
initializeDisplayPowerControllersLocked()3161     private void initializeDisplayPowerControllersLocked() {
3162         mLogicalDisplayMapper.forEachLocked(this::addDisplayPowerControllerLocked);
3163     }
3164 
3165     @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
addDisplayPowerControllerLocked( LogicalDisplay display)3166     private DisplayPowerControllerInterface addDisplayPowerControllerLocked(
3167             LogicalDisplay display) {
3168         if (mPowerHandler == null) {
3169             // initPowerManagement has not yet been called.
3170             return null;
3171         }
3172 
3173         if (mBrightnessTracker == null && display.getDisplayIdLocked() == Display.DEFAULT_DISPLAY) {
3174             mBrightnessTracker = new BrightnessTracker(mContext, null);
3175         }
3176 
3177         final int userSerial = getUserManager().getUserSerialNumber(mContext.getUserId());
3178         final BrightnessSetting brightnessSetting = new BrightnessSetting(userSerial,
3179                 mPersistentDataStore, display, mSyncRoot);
3180         final DisplayPowerControllerInterface displayPowerController;
3181 
3182         // If display is internal and has a HighBrightnessModeMetadata mapping, use that.
3183         // Or create a new one and use that.
3184         // We also need to pass a mapping of the HighBrightnessModeTimeInfoMap to
3185         // displayPowerController, so the hbm info can be correctly associated
3186         // with the corresponding displaydevice.
3187         HighBrightnessModeMetadata hbmMetadata =
3188                 mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
3189         if (mConfigParameterProvider.isNewPowerControllerFeatureEnabled()) {
3190             displayPowerController = new DisplayPowerController2(
3191                     mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
3192                     mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
3193                     () -> handleBrightnessChange(display), hbmMetadata, mBootCompleted);
3194         } else {
3195             displayPowerController = new DisplayPowerController(
3196                     mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
3197                     mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
3198                     () -> handleBrightnessChange(display), hbmMetadata, mBootCompleted);
3199         }
3200         mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController);
3201         return displayPowerController;
3202     }
3203 
handleBrightnessChange(LogicalDisplay display)3204     private void handleBrightnessChange(LogicalDisplay display) {
3205         synchronized (mSyncRoot) {
3206             sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED);
3207         }
3208     }
3209 
getDeviceForDisplayLocked(int displayId)3210     private DisplayDevice getDeviceForDisplayLocked(int displayId) {
3211         final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
3212         return display == null ? null : display.getPrimaryDisplayDeviceLocked();
3213     }
3214 
getBrightnessConfigForDisplayWithPdsFallbackLocked( String uniqueId, int userSerial)3215     private BrightnessConfiguration getBrightnessConfigForDisplayWithPdsFallbackLocked(
3216             String uniqueId, int userSerial) {
3217         BrightnessConfiguration config =
3218                 mPersistentDataStore.getBrightnessConfigurationForDisplayLocked(
3219                         uniqueId, userSerial);
3220         if (config == null) {
3221             // Get from global configurations
3222             config = mPersistentDataStore.getBrightnessConfiguration(userSerial);
3223         }
3224         return config;
3225     }
3226 
3227     private final class DisplayManagerHandler extends Handler {
DisplayManagerHandler(Looper looper)3228         public DisplayManagerHandler(Looper looper) {
3229             super(looper, null, true /*async*/);
3230         }
3231 
3232         @Override
handleMessage(Message msg)3233         public void handleMessage(Message msg) {
3234             switch (msg.what) {
3235                 case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS:
3236                     registerDefaultDisplayAdapters();
3237                     break;
3238 
3239                 case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
3240                     registerAdditionalDisplayAdapters();
3241                     break;
3242 
3243                 case MSG_DELIVER_DISPLAY_EVENT:
3244                     deliverDisplayEvent(msg.arg1, null, msg.arg2);
3245                     break;
3246 
3247                 case MSG_REQUEST_TRAVERSAL:
3248                     mWindowManagerInternal.requestTraversalFromDisplayManager();
3249                     break;
3250 
3251                 case MSG_RECEIVED_DEVICE_STATE:
3252                     mWindowManagerInternal.onDisplayManagerReceivedDeviceState(msg.arg1);
3253                     break;
3254 
3255                 case MSG_UPDATE_VIEWPORT: {
3256                     final boolean changed;
3257                     synchronized (mSyncRoot) {
3258                         changed = !mTempViewports.equals(mViewports);
3259                         if (changed) {
3260                             mTempViewports.clear();
3261                             for (DisplayViewport d : mViewports) {
3262                                 mTempViewports.add(d.makeCopy());
3263                             }
3264                         }
3265                     }
3266                     if (changed) {
3267                         mInputManagerInternal.setDisplayViewports(mTempViewports);
3268                     }
3269                     break;
3270                 }
3271 
3272                 case MSG_LOAD_BRIGHTNESS_CONFIGURATIONS:
3273                     loadBrightnessConfigurations();
3274                     break;
3275 
3276                 case MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
3277                     ArraySet<Integer> uids;
3278                     synchronized (mSyncRoot) {
3279                         int displayId = msg.arg1;
3280                         final LogicalDisplay display =
3281                                 mLogicalDisplayMapper.getDisplayLocked(displayId);
3282                         if (display == null) {
3283                             break;
3284                         }
3285                         uids = display.getPendingFrameRateOverrideUids();
3286                         display.clearPendingFrameRateOverrideUids();
3287                     }
3288                     deliverDisplayEvent(msg.arg1, uids, msg.arg2);
3289                     break;
3290 
3291                 case MSG_DELIVER_DISPLAY_GROUP_EVENT:
3292                     deliverDisplayGroupEvent(msg.arg1, msg.arg2);
3293                     break;
3294 
3295             }
3296         }
3297     }
3298 
3299     private final class LogicalDisplayListener implements LogicalDisplayMapper.Listener {
3300         @Override
onLogicalDisplayEventLocked(LogicalDisplay display, int event)3301         public void onLogicalDisplayEventLocked(LogicalDisplay display, int event) {
3302             switch (event) {
3303                 case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED:
3304                     handleLogicalDisplayAddedLocked(display);
3305                     break;
3306 
3307                 case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CHANGED:
3308                     handleLogicalDisplayChangedLocked(display);
3309                     break;
3310 
3311                 case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED:
3312                     handleLogicalDisplayRemovedLocked(display);
3313                     break;
3314 
3315                 case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_SWAPPED:
3316                     handleLogicalDisplaySwappedLocked(display);
3317                     break;
3318 
3319                 case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED:
3320                     handleLogicalDisplayFrameRateOverridesChangedLocked(display);
3321                     break;
3322 
3323                 case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION:
3324                     handleLogicalDisplayDeviceStateTransitionLocked(display);
3325                     break;
3326 
3327                 case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED:
3328                     handleLogicalDisplayHdrSdrRatioChangedLocked(display);
3329                     break;
3330             }
3331         }
3332 
3333         @Override
onDisplayGroupEventLocked(int groupId, int event)3334         public void onDisplayGroupEventLocked(int groupId, int event) {
3335             sendDisplayGroupEvent(groupId, event);
3336         }
3337 
3338         @Override
onTraversalRequested()3339         public void onTraversalRequested() {
3340             synchronized (mSyncRoot) {
3341                 scheduleTraversalLocked(false);
3342             }
3343         }
3344     }
3345 
3346     private final class CallbackRecord implements DeathRecipient {
3347         public final int mPid;
3348         public final int mUid;
3349         private final IDisplayManagerCallback mCallback;
3350         private @EventsMask AtomicLong mEventsMask;
3351 
3352         public boolean mWifiDisplayScanRequested;
3353 
CallbackRecord(int pid, int uid, IDisplayManagerCallback callback, @EventsMask long eventsMask)3354         CallbackRecord(int pid, int uid, IDisplayManagerCallback callback,
3355                 @EventsMask long eventsMask) {
3356             mPid = pid;
3357             mUid = uid;
3358             mCallback = callback;
3359             mEventsMask = new AtomicLong(eventsMask);
3360         }
3361 
updateEventsMask(@ventsMask long eventsMask)3362         public void updateEventsMask(@EventsMask long eventsMask) {
3363             mEventsMask.set(eventsMask);
3364         }
3365 
3366         @Override
binderDied()3367         public void binderDied() {
3368             if (DEBUG) {
3369                 Slog.d(TAG, "Display listener for pid " + mPid + " died.");
3370             }
3371             onCallbackDied(this);
3372         }
3373 
3374         /**
3375          * @return {@code false} if RemoteException happens; otherwise {@code true} for success.
3376          */
notifyDisplayEventAsync(int displayId, @DisplayEvent int event)3377         public boolean notifyDisplayEventAsync(int displayId, @DisplayEvent int event) {
3378             if (!shouldSendEvent(event)) {
3379                 return true;
3380             }
3381 
3382             try {
3383                 mCallback.onDisplayEvent(displayId, event);
3384                 return true;
3385             } catch (RemoteException ex) {
3386                 Slog.w(TAG, "Failed to notify process "
3387                         + mPid + " that displays changed, assuming it died.", ex);
3388                 binderDied();
3389                 return false;
3390             }
3391         }
3392 
shouldSendEvent(@isplayEvent int event)3393         private boolean shouldSendEvent(@DisplayEvent int event) {
3394             final long mask = mEventsMask.get();
3395             switch (event) {
3396                 case DisplayManagerGlobal.EVENT_DISPLAY_ADDED:
3397                     return (mask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0;
3398                 case DisplayManagerGlobal.EVENT_DISPLAY_CHANGED:
3399                     return (mask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0;
3400                 case DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED:
3401                     return (mask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0;
3402                 case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED:
3403                     return (mask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0;
3404                 case DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED:
3405                     return (mask & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0;
3406                 default:
3407                     // This should never happen.
3408                     Slog.e(TAG, "Unknown display event " + event);
3409                     return true;
3410             }
3411         }
3412     }
3413 
3414     private static final class PendingCallback {
3415         private final CallbackRecord mCallbackRecord;
3416         private final ArrayList<Pair<Integer, Integer>> mDisplayEvents;
3417 
PendingCallback(CallbackRecord cr, int displayId, int event)3418         PendingCallback(CallbackRecord cr, int displayId, int event) {
3419             mCallbackRecord = cr;
3420             mDisplayEvents = new ArrayList<>();
3421             mDisplayEvents.add(new Pair<>(displayId, event));
3422         }
3423 
addDisplayEvent(int displayId, int event)3424         public void addDisplayEvent(int displayId, int event) {
3425             // Ignore redundant events. Further optimization is possible by merging adjacent events.
3426             Pair<Integer, Integer> last = mDisplayEvents.get(mDisplayEvents.size() - 1);
3427             if (last.first == displayId && last.second == event) {
3428                 Slog.d(TAG,
3429                         "Ignore redundant display event " + displayId + "/" + event + " to "
3430                                 + mCallbackRecord.mUid + "/" + mCallbackRecord.mPid);
3431                 return;
3432             }
3433 
3434             mDisplayEvents.add(new Pair<>(displayId, event));
3435         }
3436 
sendPendingDisplayEvent()3437         public void sendPendingDisplayEvent() {
3438             for (int i = 0; i < mDisplayEvents.size(); i++) {
3439                 Pair<Integer, Integer> displayEvent = mDisplayEvents.get(i);
3440                 if (DEBUG) {
3441                     Slog.d(TAG, "Send pending display event #" + i + " " + displayEvent.first + "/"
3442                             + displayEvent.second + " to " + mCallbackRecord.mUid + "/"
3443                             + mCallbackRecord.mPid);
3444                 }
3445                 if (!mCallbackRecord.notifyDisplayEventAsync(displayEvent.first,
3446                         displayEvent.second)) {
3447                     Slog.d(TAG, "Drop pending events for dead process " + mCallbackRecord.mPid);
3448                     break;
3449                 }
3450             }
3451             mDisplayEvents.clear();
3452         }
3453     }
3454 
3455     @VisibleForTesting
3456     final class BinderService extends IDisplayManager.Stub {
3457         /**
3458          * Returns information about the specified logical display.
3459          *
3460          * @param displayId The logical display id.
3461          * @return The logical display info, return {@code null} if the display does not exist or
3462          * the calling UID isn't present on the display.  The returned object must be treated as
3463          * immutable.
3464          */
3465         @Override // Binder call
getDisplayInfo(int displayId)3466         public DisplayInfo getDisplayInfo(int displayId) {
3467             final int callingUid = Binder.getCallingUid();
3468             final long token = Binder.clearCallingIdentity();
3469             try {
3470                 return getDisplayInfoInternal(displayId, callingUid);
3471             } finally {
3472                 Binder.restoreCallingIdentity(token);
3473             }
3474         }
3475 
3476         /**
3477          * Returns the list of all display ids.
3478          */
3479         @Override // Binder call
getDisplayIds(boolean includeDisabled)3480         public int[] getDisplayIds(boolean includeDisabled) {
3481             final int callingUid = Binder.getCallingUid();
3482             final long token = Binder.clearCallingIdentity();
3483             try {
3484                 synchronized (mSyncRoot) {
3485                     return mLogicalDisplayMapper.getDisplayIdsLocked(callingUid, includeDisabled);
3486                 }
3487             } finally {
3488                 Binder.restoreCallingIdentity(token);
3489             }
3490         }
3491 
3492         @Override // Binder call
isUidPresentOnDisplay(int uid, int displayId)3493         public boolean isUidPresentOnDisplay(int uid, int displayId) {
3494             final long token = Binder.clearCallingIdentity();
3495             try {
3496                 return isUidPresentOnDisplayInternal(uid, displayId);
3497             } finally {
3498                 Binder.restoreCallingIdentity(token);
3499             }
3500         }
3501 
3502         /**
3503          * Returns the stable device display size, in pixels.
3504          */
3505         @Override // Binder call
getStableDisplaySize()3506         public Point getStableDisplaySize() {
3507             final long token = Binder.clearCallingIdentity();
3508             try {
3509                 return getStableDisplaySizeInternal();
3510             } finally {
3511                 Binder.restoreCallingIdentity(token);
3512             }
3513         }
3514 
3515         @Override // Binder call
registerCallback(IDisplayManagerCallback callback)3516         public void registerCallback(IDisplayManagerCallback callback) {
3517             registerCallbackWithEventMask(callback, DisplayManager.EVENT_FLAG_DISPLAY_ADDED
3518                     | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
3519                     | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
3520         }
3521 
3522         @Override // Binder call
registerCallbackWithEventMask(IDisplayManagerCallback callback, @EventsMask long eventsMask)3523         public void registerCallbackWithEventMask(IDisplayManagerCallback callback,
3524                 @EventsMask long eventsMask) {
3525             if (callback == null) {
3526                 throw new IllegalArgumentException("listener must not be null");
3527             }
3528 
3529             final int callingPid = Binder.getCallingPid();
3530             final int callingUid = Binder.getCallingUid();
3531             final long token = Binder.clearCallingIdentity();
3532             try {
3533                 registerCallbackInternal(callback, callingPid, callingUid, eventsMask);
3534             } finally {
3535                 Binder.restoreCallingIdentity(token);
3536             }
3537         }
3538 
3539         @Override // Binder call
startWifiDisplayScan()3540         public void startWifiDisplayScan() {
3541             mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
3542                     "Permission required to start wifi display scans");
3543 
3544             final int callingPid = Binder.getCallingPid();
3545             final long token = Binder.clearCallingIdentity();
3546             try {
3547                 startWifiDisplayScanInternal(callingPid);
3548             } finally {
3549                 Binder.restoreCallingIdentity(token);
3550             }
3551         }
3552 
3553         @Override // Binder call
stopWifiDisplayScan()3554         public void stopWifiDisplayScan() {
3555             mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
3556                     "Permission required to stop wifi display scans");
3557 
3558             final int callingPid = Binder.getCallingPid();
3559             final long token = Binder.clearCallingIdentity();
3560             try {
3561                 stopWifiDisplayScanInternal(callingPid);
3562             } finally {
3563                 Binder.restoreCallingIdentity(token);
3564             }
3565         }
3566 
3567         @Override // Binder call
connectWifiDisplay(String address)3568         public void connectWifiDisplay(String address) {
3569             if (address == null) {
3570                 throw new IllegalArgumentException("address must not be null");
3571             }
3572             mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
3573                     "Permission required to connect to a wifi display");
3574 
3575             final long token = Binder.clearCallingIdentity();
3576             try {
3577                 connectWifiDisplayInternal(address);
3578             } finally {
3579                 Binder.restoreCallingIdentity(token);
3580             }
3581         }
3582 
3583         @Override // Binder call
disconnectWifiDisplay()3584         public void disconnectWifiDisplay() {
3585             // This request does not require special permissions.
3586             // Any app can request disconnection from the currently active wifi display.
3587             // This exception should no longer be needed once wifi display control moves
3588             // to the media router service.
3589 
3590             final long token = Binder.clearCallingIdentity();
3591             try {
3592                 disconnectWifiDisplayInternal();
3593             } finally {
3594                 Binder.restoreCallingIdentity(token);
3595             }
3596         }
3597 
3598         @Override // Binder call
renameWifiDisplay(String address, String alias)3599         public void renameWifiDisplay(String address, String alias) {
3600             if (address == null) {
3601                 throw new IllegalArgumentException("address must not be null");
3602             }
3603             mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
3604                     "Permission required to rename to a wifi display");
3605 
3606             final long token = Binder.clearCallingIdentity();
3607             try {
3608                 renameWifiDisplayInternal(address, alias);
3609             } finally {
3610                 Binder.restoreCallingIdentity(token);
3611             }
3612         }
3613 
3614         @Override // Binder call
forgetWifiDisplay(String address)3615         public void forgetWifiDisplay(String address) {
3616             if (address == null) {
3617                 throw new IllegalArgumentException("address must not be null");
3618             }
3619             mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
3620                     "Permission required to forget to a wifi display");
3621 
3622             final long token = Binder.clearCallingIdentity();
3623             try {
3624                 forgetWifiDisplayInternal(address);
3625             } finally {
3626                 Binder.restoreCallingIdentity(token);
3627             }
3628         }
3629 
3630         @Override // Binder call
pauseWifiDisplay()3631         public void pauseWifiDisplay() {
3632             mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
3633                     "Permission required to pause a wifi display session");
3634 
3635             final long token = Binder.clearCallingIdentity();
3636             try {
3637                 pauseWifiDisplayInternal();
3638             } finally {
3639                 Binder.restoreCallingIdentity(token);
3640             }
3641         }
3642 
3643         @Override // Binder call
resumeWifiDisplay()3644         public void resumeWifiDisplay() {
3645             mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
3646                     "Permission required to resume a wifi display session");
3647 
3648             final long token = Binder.clearCallingIdentity();
3649             try {
3650                 resumeWifiDisplayInternal();
3651             } finally {
3652                 Binder.restoreCallingIdentity(token);
3653             }
3654         }
3655 
3656         @Override // Binder call
getWifiDisplayStatus()3657         public WifiDisplayStatus getWifiDisplayStatus() {
3658             // This request does not require special permissions.
3659             // Any app can get information about available wifi displays.
3660 
3661             final long token = Binder.clearCallingIdentity();
3662             try {
3663                 return getWifiDisplayStatusInternal();
3664             } finally {
3665                 Binder.restoreCallingIdentity(token);
3666             }
3667         }
3668 
3669         @Override // Binder call
setUserDisabledHdrTypes(int[] userDisabledFormats)3670         public void setUserDisabledHdrTypes(int[] userDisabledFormats) {
3671             mContext.enforceCallingOrSelfPermission(
3672                     Manifest.permission.WRITE_SECURE_SETTINGS,
3673                     "Permission required to write the user settings.");
3674 
3675             final long token = Binder.clearCallingIdentity();
3676             try {
3677                 setUserDisabledHdrTypesInternal(userDisabledFormats);
3678             } finally {
3679                 Binder.restoreCallingIdentity(token);
3680             }
3681         }
3682 
3683         @Override
overrideHdrTypes(int displayId, int[] modes)3684         public void overrideHdrTypes(int displayId, int[] modes) {
3685             IBinder displayToken;
3686             synchronized (mSyncRoot) {
3687                 displayToken = getDisplayToken(displayId);
3688                 if (displayToken == null) {
3689                     throw new IllegalArgumentException("Invalid display: " + displayId);
3690                 }
3691             }
3692 
3693             DisplayControl.overrideHdrTypes(displayToken, modes);
3694         }
3695 
3696         @Override // Binder call
setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed)3697         public void setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed) {
3698             mContext.enforceCallingOrSelfPermission(
3699                     Manifest.permission.WRITE_SECURE_SETTINGS,
3700                     "Permission required to write the user settings.");
3701             final long token = Binder.clearCallingIdentity();
3702             try {
3703                 setAreUserDisabledHdrTypesAllowedInternal(areUserDisabledHdrTypesAllowed);
3704             } finally {
3705                 Binder.restoreCallingIdentity(token);
3706             }
3707         }
3708 
3709         @Override // Binder call
areUserDisabledHdrTypesAllowed()3710         public boolean areUserDisabledHdrTypesAllowed() {
3711             synchronized (mSyncRoot) {
3712                 return mAreUserDisabledHdrTypesAllowed;
3713             }
3714         }
3715 
3716         @Override // Binder call
getUserDisabledHdrTypes()3717         public int[] getUserDisabledHdrTypes() {
3718             synchronized (mSyncRoot) {
3719                 return mUserDisabledHdrTypes;
3720             }
3721         }
3722 
3723         @Override // Binder call
requestColorMode(int displayId, int colorMode)3724         public void requestColorMode(int displayId, int colorMode) {
3725             mContext.enforceCallingOrSelfPermission(
3726                     Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE,
3727                     "Permission required to change the display color mode");
3728             final long token = Binder.clearCallingIdentity();
3729             try {
3730                 requestColorModeInternal(displayId, colorMode);
3731             } finally {
3732                 Binder.restoreCallingIdentity(token);
3733             }
3734         }
3735 
3736         @Override // Binder call
createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callback, IMediaProjection projection, String packageName)3737         public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
3738                 IVirtualDisplayCallback callback, IMediaProjection projection,
3739                 String packageName) {
3740             return createVirtualDisplayInternal(virtualDisplayConfig, callback, projection,
3741                     null, null, packageName);
3742         }
3743 
3744         @Override // Binder call
resizeVirtualDisplay(IVirtualDisplayCallback callback, int width, int height, int densityDpi)3745         public void resizeVirtualDisplay(IVirtualDisplayCallback callback,
3746                 int width, int height, int densityDpi) {
3747             if (width <= 0 || height <= 0 || densityDpi <= 0) {
3748                 throw new IllegalArgumentException("width, height, and densityDpi must be "
3749                         + "greater than 0");
3750             }
3751             final long token = Binder.clearCallingIdentity();
3752             try {
3753                 resizeVirtualDisplayInternal(callback.asBinder(), width, height, densityDpi);
3754             } finally {
3755                 Binder.restoreCallingIdentity(token);
3756             }
3757         }
3758 
3759         @Override // Binder call
setVirtualDisplaySurface(IVirtualDisplayCallback callback, Surface surface)3760         public void setVirtualDisplaySurface(IVirtualDisplayCallback callback, Surface surface) {
3761             if (surface != null && surface.isSingleBuffered()) {
3762                 throw new IllegalArgumentException("Surface can't be single-buffered");
3763             }
3764             final long token = Binder.clearCallingIdentity();
3765             try {
3766                 setVirtualDisplaySurfaceInternal(callback.asBinder(), surface);
3767             } finally {
3768                 Binder.restoreCallingIdentity(token);
3769             }
3770         }
3771 
3772         @Override // Binder call
releaseVirtualDisplay(IVirtualDisplayCallback callback)3773         public void releaseVirtualDisplay(IVirtualDisplayCallback callback) {
3774             final long token = Binder.clearCallingIdentity();
3775             try {
3776                 releaseVirtualDisplayInternal(callback.asBinder());
3777             } finally {
3778                 Binder.restoreCallingIdentity(token);
3779             }
3780         }
3781 
3782         @Override // Binder call
setVirtualDisplayState(IVirtualDisplayCallback callback, boolean isOn)3783         public void setVirtualDisplayState(IVirtualDisplayCallback callback, boolean isOn) {
3784             final long token = Binder.clearCallingIdentity();
3785             try {
3786                 setVirtualDisplayStateInternal(callback.asBinder(), isOn);
3787             } finally {
3788                 Binder.restoreCallingIdentity(token);
3789             }
3790         }
3791 
3792         @Override // Binder call
dump(FileDescriptor fd, final PrintWriter pw, String[] args)3793         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
3794             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
3795 
3796             final long token = Binder.clearCallingIdentity();
3797             try {
3798                 dumpInternal(pw);
3799             } finally {
3800                 Binder.restoreCallingIdentity(token);
3801             }
3802         }
3803 
3804         @Override // Binder call
getBrightnessEvents(String callingPackage)3805         public ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) {
3806             mContext.enforceCallingOrSelfPermission(
3807                     Manifest.permission.BRIGHTNESS_SLIDER_USAGE,
3808                     "Permission to read brightness events.");
3809 
3810             final int callingUid = Binder.getCallingUid();
3811             AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
3812             final int mode = appOpsManager.noteOp(AppOpsManager.OP_GET_USAGE_STATS,
3813                     callingUid, callingPackage);
3814             final boolean hasUsageStats;
3815             if (mode == AppOpsManager.MODE_DEFAULT) {
3816                 // The default behavior here is to check if PackageManager has given the app
3817                 // permission.
3818                 hasUsageStats = mContext.checkCallingPermission(
3819                         Manifest.permission.PACKAGE_USAGE_STATS)
3820                         == PackageManager.PERMISSION_GRANTED;
3821             } else {
3822                 hasUsageStats = mode == AppOpsManager.MODE_ALLOWED;
3823             }
3824 
3825             final int userId = UserHandle.getUserId(callingUid);
3826             final long token = Binder.clearCallingIdentity();
3827             try {
3828                 synchronized (mSyncRoot) {
3829                     return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
3830                             .getBrightnessEvents(userId, hasUsageStats);
3831                 }
3832             } finally {
3833                 Binder.restoreCallingIdentity(token);
3834             }
3835         }
3836 
3837         @Override // Binder call
getAmbientBrightnessStats()3838         public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats() {
3839             mContext.enforceCallingOrSelfPermission(
3840                     Manifest.permission.ACCESS_AMBIENT_LIGHT_STATS,
3841                     "Permission required to to access ambient light stats.");
3842             final int callingUid = Binder.getCallingUid();
3843             final int userId = UserHandle.getUserId(callingUid);
3844             final long token = Binder.clearCallingIdentity();
3845             try {
3846                 synchronized (mSyncRoot) {
3847                     return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
3848                             .getAmbientBrightnessStats(userId);
3849                 }
3850             } finally {
3851                 Binder.restoreCallingIdentity(token);
3852             }
3853         }
3854 
3855         @Override // Binder call
setBrightnessConfigurationForUser( BrightnessConfiguration c, @UserIdInt int userId, String packageName)3856         public void setBrightnessConfigurationForUser(
3857                 BrightnessConfiguration c, @UserIdInt int userId, String packageName) {
3858             mContext.enforceCallingOrSelfPermission(
3859                     Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS,
3860                     "Permission required to change the display's brightness configuration");
3861             if (userId != UserHandle.getCallingUserId()) {
3862                 mContext.enforceCallingOrSelfPermission(
3863                         Manifest.permission.INTERACT_ACROSS_USERS,
3864                         "Permission required to change the display brightness"
3865                                 + " configuration of another user");
3866             }
3867             final long token = Binder.clearCallingIdentity();
3868             try {
3869                 synchronized (mSyncRoot) {
3870                     mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
3871                         if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
3872                             return;
3873                         }
3874                         final DisplayDevice displayDevice =
3875                                 logicalDisplay.getPrimaryDisplayDeviceLocked();
3876                         setBrightnessConfigurationForDisplayInternal(c, displayDevice.getUniqueId(),
3877                                 userId, packageName);
3878                     });
3879                 }
3880             } finally {
3881                 Binder.restoreCallingIdentity(token);
3882             }
3883         }
3884 
3885         @Override // Binder call
setBrightnessConfigurationForDisplay(BrightnessConfiguration c, String uniqueId, int userId, String packageName)3886         public void setBrightnessConfigurationForDisplay(BrightnessConfiguration c,
3887                 String uniqueId, int userId, String packageName) {
3888             mContext.enforceCallingOrSelfPermission(
3889                     Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS,
3890                     "Permission required to change the display's brightness configuration");
3891             if (userId != UserHandle.getCallingUserId()) {
3892                 mContext.enforceCallingOrSelfPermission(
3893                         Manifest.permission.INTERACT_ACROSS_USERS,
3894                         "Permission required to change the display brightness"
3895                                 + " configuration of another user");
3896             }
3897             final long token = Binder.clearCallingIdentity();
3898             try {
3899                 setBrightnessConfigurationForDisplayInternal(c, uniqueId, userId, packageName);
3900             } finally {
3901                 Binder.restoreCallingIdentity(token);
3902             }
3903         }
3904 
3905         @Override // Binder call
getBrightnessConfigurationForDisplay(String uniqueId, int userId)3906         public BrightnessConfiguration getBrightnessConfigurationForDisplay(String uniqueId,
3907                 int userId) {
3908             mContext.enforceCallingOrSelfPermission(
3909                     Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS,
3910                     "Permission required to read the display's brightness configuration");
3911             if (userId != UserHandle.getCallingUserId()) {
3912                 mContext.enforceCallingOrSelfPermission(
3913                         Manifest.permission.INTERACT_ACROSS_USERS,
3914                         "Permission required to read the display brightness"
3915                                 + " configuration of another user");
3916             }
3917             final long token = Binder.clearCallingIdentity();
3918             final int userSerial = getUserManager().getUserSerialNumber(userId);
3919             try {
3920                 synchronized (mSyncRoot) {
3921                     // Get from per-display configurations
3922                     BrightnessConfiguration config =
3923                             getBrightnessConfigForDisplayWithPdsFallbackLocked(
3924                                     uniqueId, userSerial);
3925                     if (config == null) {
3926                         // Get default configuration
3927                         DisplayPowerControllerInterface dpc = getDpcFromUniqueIdLocked(uniqueId);
3928                         if (dpc != null) {
3929                             config = dpc.getDefaultBrightnessConfiguration();
3930                         }
3931                     }
3932                     return config;
3933                 }
3934             } finally {
3935                 Binder.restoreCallingIdentity(token);
3936             }
3937         }
3938 
3939 
3940 
3941         @Override // Binder call
getBrightnessConfigurationForUser(int userId)3942         public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) {
3943             final String uniqueId;
3944             synchronized (mSyncRoot) {
3945                 DisplayDevice displayDevice = mLogicalDisplayMapper.getDisplayLocked(
3946                         Display.DEFAULT_DISPLAY).getPrimaryDisplayDeviceLocked();
3947                 uniqueId = displayDevice.getUniqueId();
3948             }
3949             return getBrightnessConfigurationForDisplay(uniqueId, userId);
3950 
3951 
3952         }
3953 
3954         @Override // Binder call
getDefaultBrightnessConfiguration()3955         public BrightnessConfiguration getDefaultBrightnessConfiguration() {
3956             mContext.enforceCallingOrSelfPermission(
3957                     Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS,
3958                     "Permission required to read the display's default brightness configuration");
3959             final long token = Binder.clearCallingIdentity();
3960             try {
3961                 synchronized (mSyncRoot) {
3962                     return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
3963                             .getDefaultBrightnessConfiguration();
3964                 }
3965             } finally {
3966                 Binder.restoreCallingIdentity(token);
3967             }
3968         }
3969 
3970         @Override
getBrightnessInfo(int displayId)3971         public BrightnessInfo getBrightnessInfo(int displayId) {
3972             mContext.enforceCallingOrSelfPermission(
3973                     Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
3974                     "Permission required to read the display's brightness info.");
3975             final long token = Binder.clearCallingIdentity();
3976             try {
3977                 synchronized (mSyncRoot) {
3978                     LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(
3979                             displayId, /* includeDisabled= */ false);
3980                     if (display == null || !display.isEnabledLocked()) {
3981                         return null;
3982                     }
3983                     DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
3984                     if (dpc != null) {
3985                         return dpc.getBrightnessInfo();
3986                     }
3987                 }
3988             } finally {
3989                 Binder.restoreCallingIdentity(token);
3990             }
3991             return null;
3992         }
3993 
3994         @Override // Binder call
isMinimalPostProcessingRequested(int displayId)3995         public boolean isMinimalPostProcessingRequested(int displayId) {
3996             synchronized (mSyncRoot) {
3997                 return mLogicalDisplayMapper.getDisplayLocked(displayId)
3998                         .getRequestedMinimalPostProcessingLocked();
3999             }
4000         }
4001 
4002         @Override // Binder call
setTemporaryBrightness(int displayId, float brightness)4003         public void setTemporaryBrightness(int displayId, float brightness) {
4004             mContext.enforceCallingOrSelfPermission(
4005                     Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
4006                     "Permission required to set the display's brightness");
4007             final long token = Binder.clearCallingIdentity();
4008             try {
4009                 synchronized (mSyncRoot) {
4010                     mDisplayPowerControllers.get(displayId)
4011                             .setTemporaryBrightness(brightness);
4012                 }
4013             } finally {
4014                 Binder.restoreCallingIdentity(token);
4015             }
4016         }
4017 
4018         @Override // Binder call
setBrightness(int displayId, float brightness)4019         public void setBrightness(int displayId, float brightness) {
4020             mContext.enforceCallingOrSelfPermission(
4021                     Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
4022                     "Permission required to set the display's brightness");
4023             if (!isValidBrightness(brightness)) {
4024                 Slog.w(TAG, "Attempted to set invalid brightness" + brightness);
4025                 return;
4026             }
4027             final long token = Binder.clearCallingIdentity();
4028             try {
4029                 synchronized (mSyncRoot) {
4030                     DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
4031                     if (dpc != null) {
4032                         dpc.setBrightness(brightness);
4033                     }
4034                     mPersistentDataStore.saveIfNeeded();
4035                 }
4036             } finally {
4037                 Binder.restoreCallingIdentity(token);
4038             }
4039         }
4040 
4041         @Override // Binder call
getBrightness(int displayId)4042         public float getBrightness(int displayId) {
4043             float brightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
4044             mContext.enforceCallingOrSelfPermission(
4045                     Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
4046                     "Permission required to set the display's brightness");
4047             final long token = Binder.clearCallingIdentity();
4048             try {
4049                 synchronized (mSyncRoot) {
4050                     DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
4051                     if (dpc != null) {
4052                         brightness = dpc.getScreenBrightnessSetting();
4053                     }
4054                 }
4055             } finally {
4056                 Binder.restoreCallingIdentity(token);
4057             }
4058             return brightness;
4059         }
4060 
4061         @Override // Binder call
setTemporaryAutoBrightnessAdjustment(float adjustment)4062         public void setTemporaryAutoBrightnessAdjustment(float adjustment) {
4063             mContext.enforceCallingOrSelfPermission(
4064                     Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
4065                     "Permission required to set the display's auto brightness adjustment");
4066             final long token = Binder.clearCallingIdentity();
4067             try {
4068                 synchronized (mSyncRoot) {
4069                     mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
4070                             .setTemporaryAutoBrightnessAdjustment(adjustment);
4071                 }
4072             } finally {
4073                 Binder.restoreCallingIdentity(token);
4074             }
4075         }
4076 
4077         @Override // Binder call
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)4078         public void onShellCommand(FileDescriptor in, FileDescriptor out,
4079                 FileDescriptor err, String[] args, ShellCallback callback,
4080                 ResultReceiver resultReceiver) {
4081             new DisplayManagerShellCommand(DisplayManagerService.this).exec(this, in, out, err,
4082                     args, callback, resultReceiver);
4083         }
4084 
4085         @Override // Binder call
getMinimumBrightnessCurve()4086         public Curve getMinimumBrightnessCurve() {
4087             final long token = Binder.clearCallingIdentity();
4088             try {
4089                 return getMinimumBrightnessCurveInternal();
4090             } finally {
4091                 Binder.restoreCallingIdentity(token);
4092             }
4093         }
4094 
4095         @Override // Binder call
getPreferredWideGamutColorSpaceId()4096         public int getPreferredWideGamutColorSpaceId() {
4097             final long token = Binder.clearCallingIdentity();
4098             try {
4099                 return getPreferredWideGamutColorSpaceIdInternal();
4100             } finally {
4101                 Binder.restoreCallingIdentity(token);
4102             }
4103         }
4104 
4105         @Override // Binder call
setUserPreferredDisplayMode(int displayId, Display.Mode mode)4106         public void setUserPreferredDisplayMode(int displayId, Display.Mode mode) {
4107             mContext.enforceCallingOrSelfPermission(
4108                     Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE,
4109                     "Permission required to set the user preferred display mode.");
4110             final long token = Binder.clearCallingIdentity();
4111             try {
4112                 setUserPreferredDisplayModeInternal(displayId, mode);
4113             } finally {
4114                 Binder.restoreCallingIdentity(token);
4115             }
4116         }
4117 
4118         @Override // Binder call
getUserPreferredDisplayMode(int displayId)4119         public Display.Mode getUserPreferredDisplayMode(int displayId) {
4120             final long token = Binder.clearCallingIdentity();
4121             try {
4122                 return getUserPreferredDisplayModeInternal(displayId);
4123             } finally {
4124                 Binder.restoreCallingIdentity(token);
4125             }
4126         }
4127 
4128         @Override // Binder call
getSystemPreferredDisplayMode(int displayId)4129         public Display.Mode getSystemPreferredDisplayMode(int displayId) {
4130             final long token = Binder.clearCallingIdentity();
4131             try {
4132                 return getSystemPreferredDisplayModeInternal(displayId);
4133             } finally {
4134                 Binder.restoreCallingIdentity(token);
4135             }
4136         }
4137 
4138         @Override // Binder call
setHdrConversionMode(HdrConversionMode hdrConversionMode)4139         public void setHdrConversionMode(HdrConversionMode hdrConversionMode) {
4140             if (!mIsHdrOutputControlEnabled) {
4141                 return;
4142             }
4143             mContext.enforceCallingOrSelfPermission(
4144                     Manifest.permission.MODIFY_HDR_CONVERSION_MODE,
4145                     "Permission required to set the HDR conversion mode.");
4146             final long token = Binder.clearCallingIdentity();
4147             try {
4148                 setHdrConversionModeInternal(hdrConversionMode);
4149             } finally {
4150                 Binder.restoreCallingIdentity(token);
4151             }
4152         }
4153 
4154         @Override // Binder call
getHdrConversionModeSetting()4155         public HdrConversionMode getHdrConversionModeSetting() {
4156             if (!mIsHdrOutputControlEnabled) {
4157                 return HDR_CONVERSION_MODE_UNSUPPORTED;
4158             }
4159             final long token = Binder.clearCallingIdentity();
4160             try {
4161                 return getHdrConversionModeSettingInternal();
4162             } finally {
4163                 Binder.restoreCallingIdentity(token);
4164             }
4165         }
4166 
4167         @Override // Binder call
getHdrConversionMode()4168         public HdrConversionMode getHdrConversionMode() {
4169             if (!mIsHdrOutputControlEnabled) {
4170                 return HDR_CONVERSION_MODE_UNSUPPORTED;
4171             }
4172             final long token = Binder.clearCallingIdentity();
4173             try {
4174                 return getHdrConversionModeInternal();
4175             } finally {
4176                 Binder.restoreCallingIdentity(token);
4177             }
4178         }
4179 
4180         @Display.HdrCapabilities.HdrType
4181         @Override // Binder call
getSupportedHdrOutputTypes()4182         public int[] getSupportedHdrOutputTypes() {
4183             if (!mIsHdrOutputControlEnabled) {
4184                 return EMPTY_ARRAY;
4185             }
4186             final long token = Binder.clearCallingIdentity();
4187             try {
4188                 return getSupportedHdrOutputTypesInternal();
4189             } finally {
4190                 Binder.restoreCallingIdentity(token);
4191             }
4192         }
4193 
4194         @Override // Binder call
setShouldAlwaysRespectAppRequestedMode(boolean enabled)4195         public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) {
4196             mContext.enforceCallingOrSelfPermission(
4197                     Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS,
4198                     "Permission required to override display mode requests.");
4199             final long token = Binder.clearCallingIdentity();
4200             try {
4201                 setShouldAlwaysRespectAppRequestedModeInternal(enabled);
4202             } finally {
4203                 Binder.restoreCallingIdentity(token);
4204             }
4205         }
4206 
4207         @Override // Binder call
shouldAlwaysRespectAppRequestedMode()4208         public boolean shouldAlwaysRespectAppRequestedMode() {
4209             mContext.enforceCallingOrSelfPermission(
4210                     Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS,
4211                     "Permission required to override display mode requests.");
4212             final long token = Binder.clearCallingIdentity();
4213             try {
4214                 return shouldAlwaysRespectAppRequestedModeInternal();
4215             } finally {
4216                 Binder.restoreCallingIdentity(token);
4217             }
4218         }
4219 
4220         @Override // Binder call
setRefreshRateSwitchingType(int newValue)4221         public void setRefreshRateSwitchingType(int newValue) {
4222             mContext.enforceCallingOrSelfPermission(
4223                     Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE,
4224                     "Permission required to modify refresh rate switching type.");
4225             final long token = Binder.clearCallingIdentity();
4226             try {
4227                 setRefreshRateSwitchingTypeInternal(newValue);
4228             } finally {
4229                 Binder.restoreCallingIdentity(token);
4230             }
4231         }
4232 
4233         @Override // Binder call
getRefreshRateSwitchingType()4234         public int getRefreshRateSwitchingType() {
4235             final long token = Binder.clearCallingIdentity();
4236             try {
4237                 return getRefreshRateSwitchingTypeInternal();
4238             } finally {
4239                 Binder.restoreCallingIdentity(token);
4240             }
4241         }
4242 
4243         @Override // Binder call
getDisplayDecorationSupport(int displayId)4244         public DisplayDecorationSupport getDisplayDecorationSupport(int displayId) {
4245             final long token = Binder.clearCallingIdentity();
4246             try {
4247                 return getDisplayDecorationSupportInternal(displayId);
4248             } finally {
4249                 Binder.restoreCallingIdentity(token);
4250             }
4251         }
4252 
4253         @Override
setDisplayIdToMirror(IBinder token, int displayId)4254         public void setDisplayIdToMirror(IBinder token, int displayId) {
4255             synchronized (mSyncRoot) {
4256                 final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
4257                 if (mVirtualDisplayAdapter != null) {
4258                     mVirtualDisplayAdapter.setDisplayIdToMirror(token,
4259                             display == null ? Display.INVALID_DISPLAY : displayId);
4260                 }
4261             }
4262         }
4263 
4264         @Override
getOverlaySupport()4265         public OverlayProperties getOverlaySupport() {
4266             final long token = Binder.clearCallingIdentity();
4267             try {
4268                 return getOverlaySupportInternal();
4269             } finally {
4270                 Binder.restoreCallingIdentity(token);
4271             }
4272         }
4273     }
4274 
isValidBrightness(float brightness)4275     private static boolean isValidBrightness(float brightness) {
4276         return !Float.isNaN(brightness)
4277                 && (brightness >= PowerManager.BRIGHTNESS_MIN)
4278                 && (brightness <= PowerManager.BRIGHTNESS_MAX);
4279     }
4280 
isValidResolution(Point resolution)4281     private static boolean isValidResolution(Point resolution) {
4282         return (resolution != null) && (resolution.x > 0) && (resolution.y > 0);
4283     }
4284 
isValidRefreshRate(float refreshRate)4285     private static boolean isValidRefreshRate(float refreshRate) {
4286         return !Float.isNaN(refreshRate) && (refreshRate > 0.0f);
4287     }
4288 
4289     @VisibleForTesting
overrideSensorManager(SensorManager sensorManager)4290     void overrideSensorManager(SensorManager sensorManager) {
4291         synchronized (mSyncRoot) {
4292             mSensorManager = sensorManager;
4293         }
4294     }
4295 
4296     @VisibleForTesting
4297     final class LocalService extends DisplayManagerInternal {
4298 
4299         @Override
initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager)4300         public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
4301                 SensorManager sensorManager) {
4302             synchronized (mSyncRoot) {
4303                 mDisplayPowerCallbacks = callbacks;
4304                 mSensorManager = sensorManager;
4305                 mPowerHandler = handler;
4306                 initializeDisplayPowerControllersLocked();
4307             }
4308 
4309             mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS);
4310         }
4311 
4312         @Override
createVirtualDisplay(VirtualDisplayConfig config, IVirtualDisplayCallback callback, IVirtualDevice virtualDevice, DisplayWindowPolicyController dwpc, String packageName)4313         public int createVirtualDisplay(VirtualDisplayConfig config,
4314                 IVirtualDisplayCallback callback, IVirtualDevice virtualDevice,
4315                 DisplayWindowPolicyController dwpc, String packageName) {
4316             return createVirtualDisplayInternal(config, callback, null, virtualDevice, dwpc,
4317                     packageName);
4318         }
4319 
4320         @Override
requestPowerState(int groupId, DisplayPowerRequest request, boolean waitForNegativeProximity)4321         public boolean requestPowerState(int groupId, DisplayPowerRequest request,
4322                 boolean waitForNegativeProximity) {
4323             synchronized (mSyncRoot) {
4324                 final DisplayGroup displayGroup = mLogicalDisplayMapper.getDisplayGroupLocked(
4325                         groupId);
4326                 if (displayGroup == null) {
4327                     return true;
4328                 }
4329 
4330                 final int size = displayGroup.getSizeLocked();
4331                 boolean ready = true;
4332                 for (int i = 0; i < size; i++) {
4333                     final int id = displayGroup.getIdLocked(i);
4334                     final DisplayDevice displayDevice = mLogicalDisplayMapper.getDisplayLocked(
4335                             id).getPrimaryDisplayDeviceLocked();
4336                     final int flags = displayDevice.getDisplayDeviceInfoLocked().flags;
4337                     if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
4338                         final DisplayPowerControllerInterface displayPowerController =
4339                                 mDisplayPowerControllers.get(id);
4340                         ready &= displayPowerController.requestPowerState(request,
4341                                 waitForNegativeProximity);
4342                     }
4343                 }
4344 
4345                 return ready;
4346             }
4347         }
4348 
4349         @Override
isProximitySensorAvailable()4350         public boolean isProximitySensorAvailable() {
4351             synchronized (mSyncRoot) {
4352                 return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
4353                         .isProximitySensorAvailable();
4354             }
4355         }
4356 
4357         @Override
registerDisplayGroupListener(DisplayGroupListener listener)4358         public void registerDisplayGroupListener(DisplayGroupListener listener) {
4359             mDisplayGroupListeners.add(listener);
4360         }
4361 
4362         @Override
unregisterDisplayGroupListener(DisplayGroupListener listener)4363         public void unregisterDisplayGroupListener(DisplayGroupListener listener) {
4364             mDisplayGroupListeners.remove(listener);
4365         }
4366 
4367         @Override
systemScreenshot(int displayId)4368         public ScreenCapture.ScreenshotHardwareBuffer systemScreenshot(int displayId) {
4369             return systemScreenshotInternal(displayId);
4370         }
4371 
4372         @Override
userScreenshot(int displayId)4373         public ScreenCapture.ScreenshotHardwareBuffer userScreenshot(int displayId) {
4374             return userScreenshotInternal(displayId);
4375         }
4376 
4377         @Override
getDisplayInfo(int displayId)4378         public DisplayInfo getDisplayInfo(int displayId) {
4379             return getDisplayInfoInternal(displayId, Process.myUid());
4380         }
4381 
4382         @Override
getPossibleDisplayInfo(int displayId)4383         public Set<DisplayInfo> getPossibleDisplayInfo(int displayId) {
4384             synchronized (mSyncRoot) {
4385                 Set<DisplayInfo> possibleInfo = new ArraySet<>();
4386                 // For each of supported device states, retrieve the display layout of that state,
4387                 // and return all of the DisplayInfos (one per state) for the given display id.
4388                 if (mDeviceStateManager == null) {
4389                     Slog.w(TAG, "Can't get supported states since DeviceStateManager not ready");
4390                     return possibleInfo;
4391                 }
4392                 final int[] supportedStates =
4393                         mDeviceStateManager.getSupportedStateIdentifiers();
4394                 DisplayInfo displayInfo;
4395                 for (int state : supportedStates) {
4396                     displayInfo = mLogicalDisplayMapper.getDisplayInfoForStateLocked(state,
4397                             displayId);
4398                     if (displayInfo != null) {
4399                         possibleInfo.add(displayInfo);
4400                     }
4401                 }
4402                 return possibleInfo;
4403             }
4404         }
4405 
4406         @Override
getDisplayPosition(int displayId)4407         public Point getDisplayPosition(int displayId) {
4408             synchronized (mSyncRoot) {
4409                 final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
4410                 if (display != null) {
4411                     return display.getDisplayPosition();
4412                 }
4413                 return null;
4414             }
4415         }
4416 
4417         @Override
registerDisplayTransactionListener(DisplayTransactionListener listener)4418         public void registerDisplayTransactionListener(DisplayTransactionListener listener) {
4419             if (listener == null) {
4420                 throw new IllegalArgumentException("listener must not be null");
4421             }
4422 
4423             registerDisplayTransactionListenerInternal(listener);
4424         }
4425 
4426         @Override
unregisterDisplayTransactionListener(DisplayTransactionListener listener)4427         public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) {
4428             if (listener == null) {
4429                 throw new IllegalArgumentException("listener must not be null");
4430             }
4431 
4432             unregisterDisplayTransactionListenerInternal(listener);
4433         }
4434 
4435         @Override
setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info)4436         public void setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info) {
4437             setDisplayInfoOverrideFromWindowManagerInternal(displayId, info);
4438         }
4439 
4440         @Override
getNonOverrideDisplayInfo(int displayId, DisplayInfo outInfo)4441         public void getNonOverrideDisplayInfo(int displayId, DisplayInfo outInfo) {
4442             getNonOverrideDisplayInfoInternal(displayId, outInfo);
4443         }
4444 
4445         @Override
performTraversal(SurfaceControl.Transaction t)4446         public void performTraversal(SurfaceControl.Transaction t) {
4447             performTraversalInternal(t);
4448         }
4449 
4450         @Override
setDisplayProperties(int displayId, boolean hasContent, float requestedRefreshRate, int requestedMode, float requestedMinRefreshRate, float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing, boolean disableHdrConversion, boolean inTraversal)4451         public void setDisplayProperties(int displayId, boolean hasContent,
4452                 float requestedRefreshRate, int requestedMode, float requestedMinRefreshRate,
4453                 float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing,
4454                 boolean disableHdrConversion, boolean inTraversal) {
4455             setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate,
4456                     requestedMode, requestedMinRefreshRate, requestedMaxRefreshRate,
4457                     requestedMinimalPostProcessing, disableHdrConversion, inTraversal);
4458         }
4459 
4460         @Override
setDisplayOffsets(int displayId, int x, int y)4461         public void setDisplayOffsets(int displayId, int x, int y) {
4462             setDisplayOffsetsInternal(displayId, x, y);
4463         }
4464 
4465         @Override
setDisplayScalingDisabled(int displayId, boolean disableScaling)4466         public void setDisplayScalingDisabled(int displayId, boolean disableScaling) {
4467             setDisplayScalingDisabledInternal(displayId, disableScaling);
4468         }
4469 
4470         @Override
setDisplayAccessUIDs(SparseArray<IntArray> newDisplayAccessUIDs)4471         public void setDisplayAccessUIDs(SparseArray<IntArray> newDisplayAccessUIDs) {
4472             setDisplayAccessUIDsInternal(newDisplayAccessUIDs);
4473         }
4474 
4475         @Override
persistBrightnessTrackerState()4476         public void persistBrightnessTrackerState() {
4477             synchronized (mSyncRoot) {
4478                 mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
4479                         .persistBrightnessTrackerState();
4480             }
4481         }
4482 
4483         @Override
onOverlayChanged()4484         public void onOverlayChanged() {
4485             synchronized (mSyncRoot) {
4486                 mDisplayDeviceRepo.forEachLocked(DisplayDevice::onOverlayChangedLocked);
4487             }
4488         }
4489 
4490         @Override
getDisplayedContentSamplingAttributes( int displayId)4491         public DisplayedContentSamplingAttributes getDisplayedContentSamplingAttributes(
4492                 int displayId) {
4493             return getDisplayedContentSamplingAttributesInternal(displayId);
4494         }
4495 
4496         @Override
setDisplayedContentSamplingEnabled( int displayId, boolean enable, int componentMask, int maxFrames)4497         public boolean setDisplayedContentSamplingEnabled(
4498                 int displayId, boolean enable, int componentMask, int maxFrames) {
4499             return setDisplayedContentSamplingEnabledInternal(
4500                     displayId, enable, componentMask, maxFrames);
4501         }
4502 
4503         @Override
getDisplayedContentSample(int displayId, long maxFrames, long timestamp)4504         public DisplayedContentSample getDisplayedContentSample(int displayId,
4505                 long maxFrames, long timestamp) {
4506             return getDisplayedContentSampleInternal(displayId, maxFrames, timestamp);
4507         }
4508 
4509         @Override
ignoreProximitySensorUntilChanged()4510         public void ignoreProximitySensorUntilChanged() {
4511             mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
4512                     .ignoreProximitySensorUntilChanged();
4513         }
4514 
4515         @Override
getRefreshRateSwitchingType()4516         public int getRefreshRateSwitchingType() {
4517             return getRefreshRateSwitchingTypeInternal();
4518         }
4519 
4520         @Override
getRefreshRateForDisplayAndSensor(int displayId, String sensorName, String sensorType)4521         public RefreshRateRange getRefreshRateForDisplayAndSensor(int displayId, String sensorName,
4522                 String sensorType) {
4523             final SensorManager sensorManager;
4524             synchronized (mSyncRoot) {
4525                 sensorManager = mSensorManager;
4526             }
4527             if (sensorManager == null) {
4528                 return null;
4529             }
4530 
4531             // Verify that the specified sensor exists.
4532             final Sensor sensor = SensorUtils.findSensor(sensorManager, sensorType, sensorName,
4533                     SensorUtils.NO_FALLBACK);
4534             if (sensor == null) {
4535                 return null;
4536             }
4537 
4538             synchronized (mSyncRoot) {
4539                 final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
4540                 if (display == null) {
4541                     return null;
4542                 }
4543                 final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
4544                 if (device == null) {
4545                     return null;
4546                 }
4547                 final DisplayDeviceConfig config = device.getDisplayDeviceConfig();
4548                 SensorData sensorData = config.getProximitySensor();
4549                 if (sensorData != null && sensorData.matches(sensorName, sensorType)) {
4550                     return new RefreshRateRange(sensorData.minRefreshRate,
4551                             sensorData.maxRefreshRate);
4552                 }
4553             }
4554             return null;
4555         }
4556 
4557         @Override
getRefreshRateLimitations(int displayId)4558         public List<RefreshRateLimitation> getRefreshRateLimitations(int displayId) {
4559             final DisplayDeviceConfig config;
4560             synchronized (mSyncRoot) {
4561                 final DisplayDevice device = getDeviceForDisplayLocked(displayId);
4562                 if (device == null) {
4563                     return null;
4564                 }
4565                 config = device.getDisplayDeviceConfig();
4566             }
4567             return config.getRefreshRateLimitations();
4568         }
4569 
4570         @Override
setWindowManagerMirroring(int displayId, boolean isMirroring)4571         public void setWindowManagerMirroring(int displayId, boolean isMirroring) {
4572             synchronized (mSyncRoot) {
4573                 final DisplayDevice device = getDeviceForDisplayLocked(displayId);
4574                 if (device != null) {
4575                     device.setWindowManagerMirroringLocked(isMirroring);
4576                 }
4577             }
4578         }
4579 
4580         @Override
getDisplaySurfaceDefaultSize(int displayId)4581         public Point getDisplaySurfaceDefaultSize(int displayId) {
4582             final DisplayDevice device;
4583             synchronized (mSyncRoot) {
4584                 device = getDeviceForDisplayLocked(displayId);
4585                 if (device == null) {
4586                     return null;
4587                 }
4588                 return device.getDisplaySurfaceDefaultSizeLocked();
4589             }
4590         }
4591 
4592         @Override
onEarlyInteractivityChange(boolean interactive)4593         public void onEarlyInteractivityChange(boolean interactive) {
4594             mLogicalDisplayMapper.onEarlyInteractivityChange(interactive);
4595         }
4596 
4597         @Override
getDisplayWindowPolicyController(int displayId)4598         public DisplayWindowPolicyController getDisplayWindowPolicyController(int displayId) {
4599             synchronized (mSyncRoot) {
4600                 if (mDisplayWindowPolicyControllers.contains(displayId)) {
4601                     return mDisplayWindowPolicyControllers.get(displayId).second;
4602                 }
4603                 return null;
4604             }
4605         }
4606 
4607         @Override
getDisplayIdToMirror(int displayId)4608         public int getDisplayIdToMirror(int displayId) {
4609             synchronized (mSyncRoot) {
4610                 final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
4611                 if (display == null) {
4612                     return Display.INVALID_DISPLAY;
4613                 }
4614 
4615                 final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
4616                 final boolean ownContent = (displayDevice.getDisplayDeviceInfoLocked().flags
4617                         & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
4618                 // If the display has enabled mirroring, but specified that it will be managed by
4619                 // WindowManager, return an invalid display id. This is to ensure we don't
4620                 // accidentally select the display id to mirror based on DM logic and instead allow
4621                 // the caller to specify what area to mirror.
4622                 if (ownContent || displayDevice.isWindowManagerMirroringLocked()) {
4623                     return Display.INVALID_DISPLAY;
4624                 }
4625 
4626                 int displayIdToMirror = displayDevice.getDisplayIdToMirrorLocked();
4627                 LogicalDisplay displayToMirror = mLogicalDisplayMapper.getDisplayLocked(
4628                         displayIdToMirror);
4629                 // If the displayId for the requested mirror doesn't exist, fallback to mirroring
4630                 // default display.
4631                 if (displayToMirror == null) {
4632                     displayIdToMirror = Display.DEFAULT_DISPLAY;
4633                 }
4634                 return displayIdToMirror;
4635             }
4636         }
4637 
4638         @Override
getDisplayNativePrimaries(int displayId)4639         public SurfaceControl.DisplayPrimaries getDisplayNativePrimaries(int displayId) {
4640             IBinder displayToken;
4641             synchronized (mSyncRoot) {
4642                 displayToken = getDisplayToken(displayId);
4643                 if (displayToken == null) {
4644                     throw new IllegalArgumentException("Invalid displayId=" + displayId);
4645                 }
4646             }
4647 
4648             return SurfaceControl.getDisplayNativePrimaries(displayToken);
4649         }
4650 
4651         @Override
getHostUsiVersion(int displayId)4652         public HostUsiVersion getHostUsiVersion(int displayId) {
4653             synchronized (mSyncRoot) {
4654                 final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
4655                 if (display == null) {
4656                     return null;
4657                 }
4658 
4659                 return display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig()
4660                         .getHostUsiVersion();
4661             }
4662         }
4663 
4664         @Override
getAmbientLightSensorData(int displayId)4665         public AmbientLightSensorData getAmbientLightSensorData(int displayId) {
4666             synchronized (mSyncRoot) {
4667                 final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
4668                 if (display == null) {
4669                     return null;
4670                 }
4671                 final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
4672                 if (device == null) {
4673                     return null;
4674                 }
4675                 SensorData data = device.getDisplayDeviceConfig().getAmbientLightSensor();
4676                 return new AmbientLightSensorData(data.name, data.type);
4677             }
4678         }
4679 
4680         @Override
getDisplayGroupIds()4681         public IntArray getDisplayGroupIds() {
4682             Set<Integer> visitedIds = new ArraySet<>();
4683             IntArray displayGroupIds = new IntArray();
4684             synchronized (mSyncRoot) {
4685                 mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
4686                     int groupId = mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(
4687                             logicalDisplay.getDisplayIdLocked());
4688                     if (!visitedIds.contains(groupId)) {
4689                         visitedIds.add(groupId);
4690                         displayGroupIds.add(groupId);
4691                     }
4692                 });
4693             }
4694             return displayGroupIds;
4695         }
4696     }
4697 
4698     class DesiredDisplayModeSpecsObserver
4699             implements DisplayModeDirector.DesiredDisplayModeSpecsListener {
4700 
4701         private final Consumer<LogicalDisplay> mSpecsChangedConsumer = display -> {
4702             int displayId = display.getDisplayIdLocked();
4703             DisplayModeDirector.DesiredDisplayModeSpecs desiredDisplayModeSpecs =
4704                     mDisplayModeDirector.getDesiredDisplayModeSpecs(displayId);
4705             DisplayModeDirector.DesiredDisplayModeSpecs existingDesiredDisplayModeSpecs =
4706                     display.getDesiredDisplayModeSpecsLocked();
4707             if (DEBUG) {
4708                 Slog.i(TAG,
4709                         "Comparing display specs: " + desiredDisplayModeSpecs
4710                                 + ", existing: " + existingDesiredDisplayModeSpecs);
4711             }
4712             if (!desiredDisplayModeSpecs.equals(existingDesiredDisplayModeSpecs)) {
4713                 display.setDesiredDisplayModeSpecsLocked(desiredDisplayModeSpecs);
4714                 mChanged = true;
4715             }
4716         };
4717 
4718         @GuardedBy("mSyncRoot")
4719         private boolean mChanged = false;
4720 
onDesiredDisplayModeSpecsChanged()4721         public void onDesiredDisplayModeSpecsChanged() {
4722             synchronized (mSyncRoot) {
4723                 mChanged = false;
4724                 mLogicalDisplayMapper.forEachLocked(mSpecsChangedConsumer,
4725                         /* includeDisabled= */ false);
4726                 if (mChanged) {
4727                     scheduleTraversalLocked(false);
4728                     mChanged = false;
4729                 }
4730             }
4731         }
4732     }
4733 
4734     /**
4735      * Listens to changes in device state and reports the state to LogicalDisplayMapper.
4736      */
4737     class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
4738         // Base state corresponds to the physical state of the device
4739         private int mBaseState = DeviceStateManager.INVALID_DEVICE_STATE;
4740 
4741         @Override
onStateChanged(int deviceState)4742         public void onStateChanged(int deviceState) {
4743             boolean isDeviceStateOverrideActive = deviceState != mBaseState;
4744             synchronized (mSyncRoot) {
4745                 // Notify WindowManager that we are about to handle new device state, this should
4746                 // be sent before any work related to the device state in DisplayManager, so
4747                 // WindowManager could do implement that depends on the device state and display
4748                 // changes (serializes device state update and display change events)
4749                 Message msg = mHandler.obtainMessage(MSG_RECEIVED_DEVICE_STATE);
4750                 msg.arg1 = deviceState;
4751                 mHandler.sendMessage(msg);
4752 
4753                 mLogicalDisplayMapper
4754                         .setDeviceStateLocked(deviceState, isDeviceStateOverrideActive);
4755             }
4756         }
4757 
4758         @Override
onBaseStateChanged(int state)4759         public void onBaseStateChanged(int state) {
4760             mBaseState = state;
4761         }
4762     };
4763 
4764     private class BrightnessPair {
4765         public float brightness;
4766         public float sdrBrightness;
4767 
BrightnessPair(float brightness, float sdrBrightness)4768         BrightnessPair(float brightness, float sdrBrightness) {
4769             this.brightness = brightness;
4770             this.sdrBrightness = sdrBrightness;
4771         }
4772     }
4773 
4774     /**
4775      * Functional interface for providing time.
4776      * TODO(b/184781936): merge with PowerManagerService.Clock
4777      */
4778     @VisibleForTesting
4779     public interface Clock {
4780         /**
4781          * Returns current time in milliseconds since boot, not counting time spent in deep sleep.
4782          */
uptimeMillis()4783         long uptimeMillis();
4784     }
4785 }
4786