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.view.Surface.ROTATION_270;
20 import static android.view.Surface.ROTATION_90;
21 
22 import android.annotation.Nullable;
23 import android.content.Context;
24 import android.graphics.Point;
25 import android.graphics.Rect;
26 import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession;
27 import android.hardware.display.DisplayViewport;
28 import android.os.IBinder;
29 import android.util.ArraySet;
30 import android.util.Slog;
31 import android.view.Display;
32 import android.view.DisplayAddress;
33 import android.view.Surface;
34 import android.view.SurfaceControl;
35 
36 import com.android.server.display.mode.DisplayModeDirector;
37 
38 import java.io.PrintWriter;
39 import java.util.Arrays;
40 
41 /**
42  * Represents a display device such as the built-in display, an external monitor, a WiFi display,
43  * or a {@link android.hardware.display.VirtualDisplay}.
44  * <p>
45  * Display devices are guarded by the {@link DisplayManagerService.SyncRoot} lock.
46  * </p>
47  */
48 abstract class DisplayDevice {
49     /**
50      * Maximum acceptable anisotropy for the output image.
51      *
52      * Necessary to avoid unnecessary scaling when pixels are almost square, as they are non ideal
53      * anyway. For external displays, we expect an anisotropy of about 2% even if the pixels
54      * are, in fact, square due to the imprecision of the display's actual size (parsed from edid
55      * and rounded to the nearest cm).
56      */
57     static final float MAX_ANISOTROPY = 1.025f;
58     private static final String TAG = "DisplayDevice";
59     private static final Display.Mode EMPTY_DISPLAY_MODE = new Display.Mode.Builder().build();
60 
61     private final DisplayAdapter mDisplayAdapter;
62     private final IBinder mDisplayToken;
63     private final String mUniqueId;
64 
65     protected DisplayDeviceConfig mDisplayDeviceConfig;
66     // The display device does not manage these properties itself, they are set by
67     // the display manager service.  The display device shouldn't really be looking at these.
68     private int mCurrentLayerStack = -1;
69     private int mCurrentFlags = 0;
70     private int mCurrentOrientation = -1;
71     private Rect mCurrentLayerStackRect;
72     private Rect mCurrentDisplayRect;
73     private final Context mContext;
74 
75     // The display device owns its surface, but it should only set it
76     // within a transaction from performTraversalLocked.
77     private Surface mCurrentSurface;
78 
79     // DEBUG STATE: Last device info which was written to the log, or null if none.
80     // Do not use for any other purpose.
81     DisplayDeviceInfo mDebugLastLoggedDeviceInfo;
82 
83     private final boolean mIsAnisotropyCorrectionEnabled;
84 
DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, Context context)85     DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId,
86             Context context) {
87         this(displayAdapter, displayToken, uniqueId, context, false);
88     }
89 
DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, Context context, boolean isAnisotropyCorrectionEnabled)90     DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId,
91             Context context, boolean isAnisotropyCorrectionEnabled) {
92         mDisplayAdapter = displayAdapter;
93         mDisplayToken = displayToken;
94         mUniqueId = uniqueId;
95         mDisplayDeviceConfig = null;
96         mContext = context;
97         mIsAnisotropyCorrectionEnabled = isAnisotropyCorrectionEnabled;
98     }
99 
100     /**
101      * Gets the display adapter that owns the display device.
102      *
103      * @return The display adapter.
104      */
getAdapterLocked()105     public final DisplayAdapter getAdapterLocked() {
106         return mDisplayAdapter;
107     }
108 
109     /*
110      * Gets the DisplayDeviceConfig for this DisplayDevice.
111      *
112      * @return The DisplayDeviceConfig; {@code null} if not overridden.
113      */
getDisplayDeviceConfig()114     public DisplayDeviceConfig getDisplayDeviceConfig() {
115         if (mDisplayDeviceConfig == null) {
116             mDisplayDeviceConfig = loadDisplayDeviceConfig();
117         }
118         return mDisplayDeviceConfig;
119     }
120 
121     /**
122      * Gets the Surface Flinger display token for this display.
123      *
124      * @return The display token, or null if the display is not being managed
125      * by Surface Flinger.
126      */
getDisplayTokenLocked()127     public final IBinder getDisplayTokenLocked() {
128         return mDisplayToken;
129     }
130 
131     /**
132      * Gets the id of the display to mirror.
133      */
getDisplayIdToMirrorLocked()134     public int getDisplayIdToMirrorLocked() {
135         return Display.DEFAULT_DISPLAY;
136     }
137 
138     /**
139      * Returns the if WindowManager is responsible for mirroring on this display. If {@code false},
140      * then SurfaceFlinger performs no layer mirroring on this display.
141      * Only used for mirroring started from MediaProjection.
142      */
isWindowManagerMirroringLocked()143     public boolean isWindowManagerMirroringLocked() {
144         return false;
145     }
146 
147     /**
148      * Updates if WindowManager is responsible for mirroring on this display. If {@code false}, then
149      * SurfaceFlinger performs no layer mirroring to this display.
150      * Only used for mirroring started from MediaProjection.
151      */
setWindowManagerMirroringLocked(boolean isMirroring)152     public void setWindowManagerMirroringLocked(boolean isMirroring) {
153     }
154 
155     /**
156      * Returns the default size of the surface associated with the display, or null if the surface
157      * is not provided for layer mirroring by SurfaceFlinger. For non virtual displays, this will
158      * be the actual display device's size, reflecting the current rotation.
159      */
160     @Nullable
getDisplaySurfaceDefaultSizeLocked()161     public Point getDisplaySurfaceDefaultSizeLocked() {
162         DisplayDeviceInfo displayDeviceInfo = getDisplayDeviceInfoLocked();
163         var width = displayDeviceInfo.width;
164         var height = displayDeviceInfo.height;
165         if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.type == Display.TYPE_EXTERNAL
166                     && displayDeviceInfo.yDpi > 0 && displayDeviceInfo.xDpi > 0) {
167             if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * MAX_ANISOTROPY) {
168                 height = (int) (height * displayDeviceInfo.xDpi / displayDeviceInfo.yDpi + 0.5);
169             } else if (displayDeviceInfo.xDpi * MAX_ANISOTROPY < displayDeviceInfo.yDpi) {
170                 width = (int) (width * displayDeviceInfo.yDpi / displayDeviceInfo.xDpi  + 0.5);
171             }
172         }
173         return isRotatedLocked() ? new Point(height, width) : new Point(width, height);
174     }
175 
176     /**
177      * Gets the name of the display device.
178      *
179      * @return The display device name.
180      */
getNameLocked()181     public final String getNameLocked() {
182         return getDisplayDeviceInfoLocked().name;
183     }
184 
185     /**
186      * Returns the unique id of the display device.
187      */
getUniqueId()188     public final String getUniqueId() {
189         return mUniqueId;
190     }
191 
192     /**
193      * Returns whether the unique id of the device is stable across reboots.
194      */
hasStableUniqueId()195     public abstract boolean hasStableUniqueId();
196 
197     /**
198      * Gets information about the display device.
199      *
200      * The information returned should not change between calls unless the display
201      * adapter sent a {@link DisplayAdapter#DISPLAY_DEVICE_EVENT_CHANGED} event and
202      * {@link #applyPendingDisplayDeviceInfoChangesLocked()} has been called to apply
203      * the pending changes.
204      *
205      * @return The display device info, which should be treated as immutable by the caller.
206      * The display device should allocate a new display device info object whenever
207      * the data changes.
208      */
getDisplayDeviceInfoLocked()209     public abstract DisplayDeviceInfo getDisplayDeviceInfoLocked();
210 
211     /**
212      * Applies any pending changes to the observable state of the display device
213      * if the display adapter sent a {@link DisplayAdapter#DISPLAY_DEVICE_EVENT_CHANGED} event.
214      */
applyPendingDisplayDeviceInfoChangesLocked()215     public void applyPendingDisplayDeviceInfoChangesLocked() {
216     }
217 
218     /**
219      * Gives the display device a chance to update its properties while in a transaction.
220      */
performTraversalLocked(SurfaceControl.Transaction t)221     public void performTraversalLocked(SurfaceControl.Transaction t) {
222     }
223 
224     /**
225      * Sets the display state, if supported.
226      *
227      * @param state The new display state.
228      * @param brightnessState The new display brightnessState.
229      * @param sdrBrightnessState The new display brightnessState for SDR layers.
230      * @param displayOffloadSession {@link DisplayOffloadSession} associated with current device.
231      * @return A runnable containing work to be deferred until after we have exited the critical
232      *     section, or null if none.
233      */
requestDisplayStateLocked( int state, float brightnessState, float sdrBrightnessState, @Nullable DisplayOffloadSessionImpl displayOffloadSession)234     public Runnable requestDisplayStateLocked(
235             int state,
236             float brightnessState,
237             float sdrBrightnessState,
238             @Nullable DisplayOffloadSessionImpl displayOffloadSession) {
239         return null;
240     }
241 
242     /**
243      * Sets the display mode specs.
244      *
245      * Not all display devices will automatically switch between modes, so it's important that the
246      * default modeId is set correctly.
247      */
setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs)248     public void setDesiredDisplayModeSpecsLocked(
249             DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {}
250 
251     /**
252      * Sets the user preferred display mode. Removes the user preferred display mode and sets
253      * default display mode as the mode chosen by HAL, if 'mode' is null
254      * Returns true if the mode set by user is supported by the display.
255      */
setUserPreferredDisplayModeLocked(Display.Mode mode)256     public void setUserPreferredDisplayModeLocked(Display.Mode mode) { }
257 
258     /**
259      * Returns the user preferred display mode.
260      */
getUserPreferredDisplayModeLocked()261     public Display.Mode getUserPreferredDisplayModeLocked() {
262         return EMPTY_DISPLAY_MODE;
263     }
264 
265     /**
266      * Returns the system preferred display mode.
267      */
getSystemPreferredDisplayModeLocked()268     public Display.Mode getSystemPreferredDisplayModeLocked() {
269         return EMPTY_DISPLAY_MODE;
270     }
271 
272     /**
273      * Returns the display mode that was being used when this display was first found by
274      * display manager.
275      * @hide
276      */
getActiveDisplayModeAtStartLocked()277     public Display.Mode getActiveDisplayModeAtStartLocked() {
278         return EMPTY_DISPLAY_MODE;
279     }
280 
281     /**
282      * Sets the requested color mode.
283      */
setRequestedColorModeLocked(int colorMode)284     public void setRequestedColorModeLocked(int colorMode) {
285     }
286 
287     /**
288      * Sends the Auto Low Latency Mode (ALLM) signal over HDMI, or requests an internal display to
289      * switch to a low-latency mode.
290      *
291      * @param on Whether to set ALLM on or off.
292      */
setAutoLowLatencyModeLocked(boolean on)293     public void setAutoLowLatencyModeLocked(boolean on) {
294     }
295 
296     /**
297      * Sends a ContentType=Game signal over HDMI, or requests an internal display to switch to a
298      * game mode (generally lower latency).
299      *
300      * @param on Whether to send a ContentType=Game signal or not
301      */
setGameContentTypeLocked(boolean on)302     public void setGameContentTypeLocked(boolean on) {
303     }
304 
onOverlayChangedLocked()305     public void onOverlayChangedLocked() {
306     }
307 
308     /**
309      * Sets the display layer stack while in a transaction.
310      */
setLayerStackLocked(SurfaceControl.Transaction t, int layerStack, int layerStackTag)311     public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack,
312             int layerStackTag) {
313         if (mCurrentLayerStack != layerStack) {
314             mCurrentLayerStack = layerStack;
315             t.setDisplayLayerStack(mDisplayToken, layerStack);
316             Slog.i(TAG, "[" + layerStackTag + "] Layerstack set to " + layerStack + " for "
317                     + mUniqueId);
318         }
319     }
320 
321     /**
322      * Sets the display flags while in a transaction.
323      *
324      * Valid display flags:
325      *  {@link SurfaceControl#DISPLAY_RECEIVES_INPUT}
326      */
setDisplayFlagsLocked(SurfaceControl.Transaction t, int flags)327     public final void setDisplayFlagsLocked(SurfaceControl.Transaction t, int flags) {
328         if (mCurrentFlags != flags) {
329             mCurrentFlags = flags;
330             t.setDisplayFlags(mDisplayToken, flags);
331         }
332     }
333 
334     /**
335      * Sets the display projection while in a transaction.
336      *
337      * @param orientation defines the display's orientation
338      * @param layerStackRect defines which area of the window manager coordinate
339      *            space will be used
340      * @param displayRect defines where on the display will layerStackRect be
341      *            mapped to. displayRect is specified post-orientation, that is
342      *            it uses the orientation seen by the end-user
343      */
setProjectionLocked(SurfaceControl.Transaction t, int orientation, Rect layerStackRect, Rect displayRect)344     public final void setProjectionLocked(SurfaceControl.Transaction t, int orientation,
345             Rect layerStackRect, Rect displayRect) {
346         if (mCurrentOrientation != orientation
347                 || mCurrentLayerStackRect == null
348                 || !mCurrentLayerStackRect.equals(layerStackRect)
349                 || mCurrentDisplayRect == null
350                 || !mCurrentDisplayRect.equals(displayRect)) {
351             mCurrentOrientation = orientation;
352 
353             if (mCurrentLayerStackRect == null) {
354                 mCurrentLayerStackRect = new Rect();
355             }
356             mCurrentLayerStackRect.set(layerStackRect);
357 
358             if (mCurrentDisplayRect == null) {
359                 mCurrentDisplayRect = new Rect();
360             }
361             mCurrentDisplayRect.set(displayRect);
362 
363             t.setDisplayProjection(mDisplayToken,
364                     orientation, layerStackRect, displayRect);
365         }
366     }
367 
368     /**
369      * Sets the display surface while in a transaction.
370      */
setSurfaceLocked(SurfaceControl.Transaction t, Surface surface)371     public final void setSurfaceLocked(SurfaceControl.Transaction t, Surface surface) {
372         if (mCurrentSurface != surface) {
373             mCurrentSurface = surface;
374             t.setDisplaySurface(mDisplayToken, surface);
375         }
376     }
377 
378     /**
379      * Populates the specified viewport object with orientation,
380      * physical and logical rects based on the display's current projection.
381      */
populateViewportLocked(DisplayViewport viewport)382     public final void populateViewportLocked(DisplayViewport viewport) {
383         viewport.orientation = mCurrentOrientation;
384 
385         if (mCurrentLayerStackRect != null) {
386             viewport.logicalFrame.set(mCurrentLayerStackRect);
387         } else {
388             viewport.logicalFrame.setEmpty();
389         }
390 
391         if (mCurrentDisplayRect != null) {
392             viewport.physicalFrame.set(mCurrentDisplayRect);
393         } else {
394             viewport.physicalFrame.setEmpty();
395         }
396 
397         final boolean isRotated = isRotatedLocked();
398         DisplayDeviceInfo info = getDisplayDeviceInfoLocked();
399         viewport.deviceWidth = isRotated ? info.height : info.width;
400         viewport.deviceHeight = isRotated ? info.width : info.height;
401 
402         viewport.uniqueId = info.uniqueId;
403 
404         if (info.address instanceof DisplayAddress.Physical) {
405             viewport.physicalPort = ((DisplayAddress.Physical) info.address).getPort();
406         } else {
407             viewport.physicalPort = null;
408         }
409     }
410 
411     /**
412      * Dumps the local state of the display device.
413      * Does not need to dump the display device info because that is already dumped elsewhere.
414      */
dumpLocked(PrintWriter pw)415     public void dumpLocked(PrintWriter pw) {
416         pw.println("mAdapter=" + mDisplayAdapter.getName());
417         pw.println("mUniqueId=" + mUniqueId);
418         pw.println("mDisplayToken=" + mDisplayToken);
419         pw.println("mCurrentLayerStack=" + mCurrentLayerStack);
420         pw.println("mCurrentFlags=" + mCurrentFlags);
421         pw.println("mCurrentOrientation=" + mCurrentOrientation);
422         pw.println("mCurrentLayerStackRect=" + mCurrentLayerStackRect);
423         pw.println("mCurrentDisplayRect=" + mCurrentDisplayRect);
424         pw.println("mCurrentSurface=" + mCurrentSurface);
425     }
426 
427     /**
428      * @return whether the orientation is {@link ROTATION_90} or {@link ROTATION_270}.
429      */
isRotatedLocked()430     boolean isRotatedLocked() {
431         return mCurrentOrientation == ROTATION_90 || mCurrentOrientation == ROTATION_270;
432     }
433 
434     /**
435      * @return set of supported resolutions as an ascending sorted array.
436      */
getSupportedResolutionsLocked()437     Point[] getSupportedResolutionsLocked() {
438         ArraySet<Point> resolutions = new ArraySet<>(2);
439         Display.Mode[] supportedModes = getDisplayDeviceInfoLocked().supportedModes;
440         for (Display.Mode mode : supportedModes) {
441             resolutions.add(new Point(mode.getPhysicalWidth(), mode.getPhysicalHeight()));
442         }
443         Point[] sortedArray = new Point[resolutions.size()];
444         resolutions.toArray(sortedArray);
445         Arrays.sort(sortedArray, (p1, p2) -> p1.x * p1.y - p2.x * p2.y);
446         return sortedArray;
447     }
448 
loadDisplayDeviceConfig()449     private DisplayDeviceConfig loadDisplayDeviceConfig() {
450         return DisplayDeviceConfig.create(mContext, /* useConfigXml= */ false,
451                 mDisplayAdapter.getFeatureFlags());
452     }
453 }
454