• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.display;
18 
19 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
20 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
21 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
22 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
23 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP;
24 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
25 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
26 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
27 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
28 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
29 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
30 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
31 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED;
32 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
33 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED;
34 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
35 
36 import android.annotation.Nullable;
37 import android.content.Context;
38 import android.graphics.Point;
39 import android.hardware.display.IBrightnessListener;
40 import android.hardware.display.IVirtualDisplayCallback;
41 import android.hardware.display.VirtualDisplayConfig;
42 import android.media.projection.IMediaProjection;
43 import android.media.projection.IMediaProjectionCallback;
44 import android.os.Handler;
45 import android.os.IBinder;
46 import android.os.IBinder.DeathRecipient;
47 import android.os.Message;
48 import android.os.PowerManager;
49 import android.os.RemoteException;
50 import android.os.SystemProperties;
51 import android.util.ArrayMap;
52 import android.util.Slog;
53 import android.util.SparseIntArray;
54 import android.view.Display;
55 import android.view.DisplayCutout;
56 import android.view.DisplayShape;
57 import android.view.Surface;
58 import android.view.SurfaceControl;
59 
60 import com.android.internal.R;
61 import com.android.internal.annotations.VisibleForTesting;
62 import com.android.server.display.brightness.BrightnessUtils;
63 import com.android.server.display.feature.DisplayManagerFlags;
64 
65 import java.io.PrintWriter;
66 import java.util.concurrent.atomic.AtomicInteger;
67 
68 /**
69  * A display adapter that provides virtual displays on behalf of applications.
70  * <p>
71  * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
72  * </p>
73  */
74 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
75 public class VirtualDisplayAdapter extends DisplayAdapter {
76     static final String TAG = "VirtualDisplayAdapter";
77 
78     // Unique id prefix for virtual displays
79     @VisibleForTesting
80     static final String UNIQUE_ID_PREFIX = "virtual:";
81 
82     // Unique id suffix for virtual displays
83     private static final AtomicInteger sNextUniqueIndex = new AtomicInteger(0);
84 
85     private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices = new ArrayMap<>();
86 
87     // When a virtual display is created, the mapping (appToken -> ownerUid) is stored here. That
88     // way, when the display is released later, we can retrieve the ownerUid and decrement
89     // the number of virtual displays that exist for that ownerUid. We can't use
90     // Binder.getCallingUid() because the display might be released by the system process and not
91     // the process that created the display.
92     private final ArrayMap<IBinder, Integer> mOwnerUids = new ArrayMap<>();
93 
94     private final int mMaxDevices;
95     private final int mMaxDevicesPerPackage;
96     private final SparseIntArray mNoOfDevicesPerPackage = new SparseIntArray();
97 
98     private final Handler mHandler;
99     private final SurfaceControlDisplayFactory mSurfaceControlDisplayFactory;
100 
101     // Called with SyncRoot lock held.
VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, DisplayManagerFlags featureFlags)102     public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
103             Context context, Handler handler, Listener listener, DisplayManagerFlags featureFlags) {
104         this(syncRoot, context, handler, listener, new SurfaceControlDisplayFactory() {
105             @Override
106             public IBinder createDisplay(String name, boolean secure, boolean optimizeForPower,
107                     String uniqueId, float requestedRefreshRate) {
108                 return DisplayControl.createVirtualDisplay(name, secure, optimizeForPower, uniqueId,
109                         requestedRefreshRate);
110             }
111 
112             @Override
113             public void destroyDisplay(IBinder displayToken) {
114                 DisplayControl.destroyVirtualDisplay(displayToken);
115             }
116 
117             @Override
118             public void setDisplayPowerMode(IBinder displayToken, int mode) {
119                 SurfaceControl.setDisplayPowerMode(displayToken, mode);
120             }
121         }, featureFlags);
122     }
123 
124     @VisibleForTesting
VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, SurfaceControlDisplayFactory surfaceControlDisplayFactory, DisplayManagerFlags featureFlags)125     VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
126             Context context, Handler handler, Listener listener,
127             SurfaceControlDisplayFactory surfaceControlDisplayFactory,
128             DisplayManagerFlags featureFlags) {
129         super(syncRoot, context, handler, listener, TAG, featureFlags);
130         mHandler = handler;
131         mSurfaceControlDisplayFactory = surfaceControlDisplayFactory;
132 
133         mMaxDevices = context.getResources().getInteger(R.integer.config_virtualDisplayLimit);
134         if (mMaxDevices < 1) {
135             throw new IllegalArgumentException("The limit of virtual displays must be >= 1");
136         }
137         mMaxDevicesPerPackage =
138                 context.getResources().getInteger(R.integer.config_virtualDisplayLimitPerPackage);
139         if (mMaxDevicesPerPackage < 1) {
140             throw new IllegalArgumentException(
141                     "The limit of virtual displays per package must be >= 1");
142         }
143     }
144 
145     /**
146      * Create a virtual display
147      * @param callback The callback
148      * @param projection The media projection
149      * @param ownerUid The UID of the package creating a display
150      * @param ownerPackageName The name of the package creating a display
151      * @param uniqueId The unique ID of the display device
152      * @param surface The surface
153      * @param flags The flags
154      * @param virtualDisplayConfig The config
155      * @return The display device created
156      */
createVirtualDisplayLocked(IVirtualDisplayCallback callback, IMediaProjection projection, int ownerUid, String ownerPackageName, String uniqueId, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig)157     public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
158             IMediaProjection projection, int ownerUid, String ownerPackageName, String uniqueId,
159             Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig) {
160         IBinder appToken = callback.asBinder();
161         if (mVirtualDisplayDevices.containsKey(appToken)) {
162             Slog.wtfStack(TAG,
163                     "Can't create virtual display, display with same appToken already exists");
164             return null;
165         }
166 
167         if (getFeatureFlags().isVirtualDisplayLimitEnabled()
168                 && mVirtualDisplayDevices.size() >= mMaxDevices) {
169             Slog.w(TAG, "Rejecting request to create private virtual display because "
170                     + mMaxDevices + " devices already exist.");
171             return null;
172         }
173 
174         int noOfDevices = mNoOfDevicesPerPackage.get(ownerUid, /* valueIfKeyNotFound= */ 0);
175         if (getFeatureFlags().isVirtualDisplayLimitEnabled()
176                 && noOfDevices >= mMaxDevicesPerPackage) {
177             Slog.w(TAG, "Rejecting request to create private virtual display because "
178                     + mMaxDevicesPerPackage + " devices already exist for package "
179                     + ownerPackageName + ".");
180             return null;
181         }
182 
183         String name = virtualDisplayConfig.getName();
184         boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
185         boolean neverBlank = isNeverBlank(flags);
186 
187         // Never-blank displays are considered to be dependent on another display to be rendered.
188         // As a result, such displays should optimize for power instead of performance when it is
189         // powered on.
190         IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure, neverBlank,
191                 uniqueId, virtualDisplayConfig.getRequestedRefreshRate());
192         MediaProjectionCallback mediaProjectionCallback =  null;
193         if (projection != null) {
194             mediaProjectionCallback = new MediaProjectionCallback(appToken);
195         }
196 
197         Callback callbackDelegate = new Callback(
198                 callback, virtualDisplayConfig.getBrightnessListener(), mHandler);
199         VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
200                 ownerUid, ownerPackageName, surface, flags, callbackDelegate,
201                 projection, mediaProjectionCallback, uniqueId, virtualDisplayConfig);
202 
203         mVirtualDisplayDevices.put(appToken, device);
204         if (getFeatureFlags().isVirtualDisplayLimitEnabled()) {
205             mNoOfDevicesPerPackage.put(ownerUid, noOfDevices + 1);
206             mOwnerUids.put(appToken, ownerUid);
207         }
208 
209         try {
210             if (projection != null) {
211                 projection.registerCallback(mediaProjectionCallback);
212                 Slog.d(TAG, "Virtual Display: registered media projection callback for new "
213                         + "VirtualDisplayDevice");
214             }
215             appToken.linkToDeath(device, 0);
216         } catch (RemoteException ex) {
217             Slog.e(TAG, "Virtual Display: error while setting up VirtualDisplayDevice", ex);
218             removeVirtualDisplayDeviceLocked(appToken);
219             device.destroyLocked(false);
220             return null;
221         }
222 
223         // Return the display device without actually sending the event indicating
224         // that it was added.  The caller will handle it.
225         return device;
226     }
227 
resizeVirtualDisplayLocked(IBinder appToken, int width, int height, int densityDpi)228     public void resizeVirtualDisplayLocked(IBinder appToken,
229             int width, int height, int densityDpi) {
230         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
231         if (device != null) {
232             Slog.v(TAG, "Resize VirtualDisplay " + device.mName + " to " + width
233                     + " " + height);
234             device.resizeLocked(width, height, densityDpi);
235         }
236     }
237 
238     @VisibleForTesting
getVirtualDisplaySurfaceLocked(IBinder appToken)239     Surface getVirtualDisplaySurfaceLocked(IBinder appToken) {
240         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
241         if (device != null) {
242             return device.getSurfaceLocked();
243         }
244         return null;
245     }
246 
setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface)247     public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) {
248         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
249         if (device != null) {
250             Slog.v(TAG, "Update surface for VirtualDisplay " + device.mName);
251             device.setSurfaceLocked(surface);
252         }
253     }
254 
setDisplayIdToMirror(IBinder appToken, int displayId)255     void setDisplayIdToMirror(IBinder appToken, int displayId) {
256         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
257         if (device != null) {
258             device.setDisplayIdToMirror(displayId);
259         }
260     }
261 
262     /**
263      * Release a virtual display that was previously created
264      * @param appToken The token to identify the display
265      * @return The display device that has been removed
266      */
releaseVirtualDisplayLocked(IBinder appToken)267     public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) {
268         VirtualDisplayDevice device = removeVirtualDisplayDeviceLocked(appToken);
269         if (device != null) {
270             Slog.v(TAG, "Release VirtualDisplay " + device.mName);
271             device.destroyLocked(true);
272             appToken.unlinkToDeath(device, 0);
273         }
274 
275         // Return the display device that was removed without actually sending the
276         // event indicating that it was removed.  The caller will handle it.
277         return device;
278     }
279 
getDisplayDevice(IBinder appToken)280     DisplayDevice getDisplayDevice(IBinder appToken) {
281         return mVirtualDisplayDevices.get(appToken);
282     }
283 
284     /**
285      * Generates a virtual display's unique identifier.
286      *
287      * <p>It is always prefixed with "virtual:package-name". If the provided config explicitly
288      * specifies a unique ID, then it's simply appended. Otherwise, the UID, display name and a
289      * unique index are appended.</p>
290      *
291      * <p>The unique index is incremented for every virtual display unique ID generation and serves
292      * for differentiating between displays with the same name created by the same owner.</p>
293      */
generateDisplayUniqueId(String packageName, int uid, VirtualDisplayConfig config)294     static String generateDisplayUniqueId(String packageName, int uid,
295             VirtualDisplayConfig config) {
296         return UNIQUE_ID_PREFIX + packageName + ((config.getUniqueId() != null)
297                 ? (":" + config.getUniqueId())
298                 : ("," + uid + "," + config.getName() + "," + sNextUniqueIndex.getAndIncrement()));
299     }
300 
handleMediaProjectionStoppedLocked(IBinder appToken)301     private void handleMediaProjectionStoppedLocked(IBinder appToken) {
302         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
303         if (device != null) {
304             Slog.i(TAG, "Virtual display device released because media projection stopped: "
305                     + device.mName);
306             device.stopLocked();
307         }
308     }
309 
removeVirtualDisplayDeviceLocked(IBinder appToken)310     private VirtualDisplayDevice removeVirtualDisplayDeviceLocked(IBinder appToken) {
311         if (getFeatureFlags().isVirtualDisplayLimitEnabled()) {
312             Integer ownerUid = mOwnerUids.remove(appToken);
313             if (ownerUid != null) {
314                 int noOfDevices = mNoOfDevicesPerPackage.get(ownerUid, /* valueIfKeyNotFound= */ 0);
315                 if (noOfDevices <= 1) {
316                     mNoOfDevicesPerPackage.delete(ownerUid);
317                 } else {
318                     mNoOfDevicesPerPackage.put(ownerUid, noOfDevices - 1);
319                 }
320             }
321         }
322         return mVirtualDisplayDevices.remove(appToken);
323     }
324 
isNeverBlank(int flags)325     private static boolean isNeverBlank(int flags) {
326         // Private non-mirror displays are never blank and always on.
327         return (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0
328                 && (flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0;
329     }
330 
331     private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient {
332         private static final int PENDING_SURFACE_CHANGE = 0x01;
333         private static final int PENDING_RESIZE = 0x02;
334 
335         private static final float REFRESH_RATE = 60.0f;
336 
337         private final IBinder mAppToken;
338         private final int mOwnerUid;
339         final String mOwnerPackageName;
340         final String mName;
341         private final int mFlags;
342         private final Callback mCallback;
343         @Nullable private final IMediaProjection mProjection;
344         @Nullable private final IMediaProjectionCallback mMediaProjectionCallback;
345 
346         private int mWidth;
347         private int mHeight;
348         private int mDensityDpi;
349         private final float mRequestedRefreshRate;
350         private Surface mSurface;
351         private DisplayDeviceInfo mInfo;
352         private int mDisplayState;
353         private boolean mStopped;
354         private int mPendingChanges;
355         private Display.Mode mMode;
356         private int mDisplayIdToMirror;
357         private boolean mIsWindowManagerMirroring;
358         private final boolean mNeverBlank;
359         private final DisplayCutout mDisplayCutout;
360         private final float mDefaultBrightness;
361         private final float mDimBrightness;
362         private float mCurrentBrightness;
363         private final IBrightnessListener mBrightnessListener;
364 
VirtualDisplayDevice(IBinder displayToken, IBinder appToken, int ownerUid, String ownerPackageName, Surface surface, int flags, Callback callback, IMediaProjection projection, IMediaProjectionCallback mediaProjectionCallback, String uniqueId, VirtualDisplayConfig virtualDisplayConfig)365         public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
366                 int ownerUid, String ownerPackageName, Surface surface, int flags,
367                 Callback callback, IMediaProjection projection,
368                 IMediaProjectionCallback mediaProjectionCallback, String uniqueId,
369                 VirtualDisplayConfig virtualDisplayConfig) {
370             super(VirtualDisplayAdapter.this, displayToken, uniqueId, getContext());
371             mAppToken = appToken;
372             mOwnerUid = ownerUid;
373             mOwnerPackageName = ownerPackageName;
374             mName = virtualDisplayConfig.getName();
375             mWidth = virtualDisplayConfig.getWidth();
376             mHeight = virtualDisplayConfig.getHeight();
377             mDensityDpi = virtualDisplayConfig.getDensityDpi();
378             mRequestedRefreshRate = virtualDisplayConfig.getRequestedRefreshRate();
379             mDisplayCutout = virtualDisplayConfig.getDisplayCutout();
380             mDefaultBrightness = virtualDisplayConfig.getDefaultBrightness();
381             mDimBrightness = virtualDisplayConfig.getDimBrightness();
382             mCurrentBrightness = PowerManager.BRIGHTNESS_INVALID;
383             mBrightnessListener = virtualDisplayConfig.getBrightnessListener();
384             mMode = createMode(mWidth, mHeight, getRefreshRate());
385             mSurface = surface;
386             mFlags = flags;
387             mCallback = callback;
388             mProjection = projection;
389             mMediaProjectionCallback = mediaProjectionCallback;
390             mNeverBlank = isNeverBlank(flags);
391             if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()
392                     && !mNeverBlank) {
393                 // The display's power state depends on the power state of the state of its
394                 // display / power group, which we don't know here. Initializing to UNKNOWN allows
395                 // the first call to requestDisplayStateLocked() to set the correct state.
396                 // This also triggers VirtualDisplay.Callback to tell the owner the initial state.
397                 mDisplayState = Display.STATE_UNKNOWN;
398             } else {
399                 mDisplayState = Display.STATE_ON;
400             }
401             mPendingChanges |= PENDING_SURFACE_CHANGE;
402             mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror();
403             mIsWindowManagerMirroring = virtualDisplayConfig.isWindowManagerMirroringEnabled();
404         }
405 
406         @Override
binderDied()407         public void binderDied() {
408             synchronized (getSyncRoot()) {
409                 removeVirtualDisplayDeviceLocked(mAppToken);
410                 Slog.i(TAG, "Virtual display device released because application token died: "
411                     + mOwnerPackageName);
412                 destroyLocked(false);
413                 if (mProjection != null && mMediaProjectionCallback != null) {
414                     try {
415                         mProjection.unregisterCallback(mMediaProjectionCallback);
416                     } catch (RemoteException e) {
417                         Slog.w(TAG, "Failed to unregister callback in binderDied", e);
418                     }
419                 }
420                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_REMOVED);
421             }
422         }
423 
destroyLocked(boolean binderAlive)424         public void destroyLocked(boolean binderAlive) {
425             if (mSurface != null) {
426                 mSurface.release();
427                 mSurface = null;
428             }
429             mSurfaceControlDisplayFactory.destroyDisplay(getDisplayTokenLocked());
430             if (mProjection != null && mMediaProjectionCallback != null) {
431                 try {
432                     mProjection.unregisterCallback(mMediaProjectionCallback);
433                 } catch (RemoteException e) {
434                     Slog.w(TAG, "Failed to unregister callback in destroy", e);
435                 }
436             }
437             if (binderAlive) {
438                 mCallback.dispatchDisplayStopped();
439             }
440         }
441 
442         @Override
getDisplayIdToMirrorLocked()443         public int getDisplayIdToMirrorLocked() {
444             return mDisplayIdToMirror;
445         }
446 
setDisplayIdToMirror(int displayIdToMirror)447         void setDisplayIdToMirror(int displayIdToMirror) {
448             if (mDisplayIdToMirror != displayIdToMirror) {
449                 mDisplayIdToMirror = displayIdToMirror;
450                 mInfo = null;
451                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
452                 sendTraversalRequestLocked();
453             }
454         }
455 
456         @Override
isWindowManagerMirroringLocked()457         public boolean isWindowManagerMirroringLocked() {
458             return mIsWindowManagerMirroring;
459         }
460 
461         @Override
setWindowManagerMirroringLocked(boolean mirroring)462         public void setWindowManagerMirroringLocked(boolean mirroring) {
463             if (mIsWindowManagerMirroring != mirroring) {
464                 mIsWindowManagerMirroring = mirroring;
465                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
466                 sendTraversalRequestLocked();
467             }
468         }
469 
470         @Override
getDisplaySurfaceDefaultSizeLocked()471         public Point getDisplaySurfaceDefaultSizeLocked() {
472             if (mSurface == null) {
473                 return null;
474             }
475             final Point surfaceSize = mSurface.getDefaultSize();
476             return isRotatedLocked() ? new Point(surfaceSize.y, surfaceSize.x) : surfaceSize;
477         }
478 
479         @VisibleForTesting
getSurfaceLocked()480         Surface getSurfaceLocked() {
481             return mSurface;
482         }
483 
484         @Override
hasStableUniqueId()485         public boolean hasStableUniqueId() {
486             return false;
487         }
488 
489         @Override
requestDisplayStateLocked(int state, float brightnessState, float sdrBrightnessState, DisplayOffloadSessionImpl displayOffloadSession)490         public Runnable requestDisplayStateLocked(int state, float brightnessState,
491                 float sdrBrightnessState, DisplayOffloadSessionImpl displayOffloadSession) {
492             Runnable runnable = null;
493             if (state != mDisplayState) {
494                 Slog.d(TAG, "Changing state of virtual display " + mName + " from "
495                         + Display.stateToString(mDisplayState) + " to "
496                         + Display.stateToString(state));
497                 if (state != Display.STATE_ON && state != Display.STATE_OFF) {
498                     Slog.wtf(TAG, "Unexpected display state for Virtual Display: "
499                             + Display.stateToString(state));
500                 }
501                 mDisplayState = state;
502                 mInfo = null;
503                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
504                 if (state == Display.STATE_OFF) {
505                     mCallback.dispatchDisplayPaused();
506                 } else {
507                     mCallback.dispatchDisplayResumed();
508                 }
509 
510                 if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
511                     final IBinder token = getDisplayTokenLocked();
512                     runnable = () -> {
513                         final int mode = getPowerModeForState(state);
514                         Slog.d(TAG, "Requesting power mode for display " + mName + " to " + mode);
515                         mSurfaceControlDisplayFactory.setDisplayPowerMode(token, mode);
516                     };
517                 }
518             }
519             if (android.companion.virtualdevice.flags.Flags.deviceAwareDisplayPower()
520                     && mBrightnessListener != null
521                     && BrightnessUtils.isValidBrightnessValue(brightnessState)
522                     && brightnessState != mCurrentBrightness) {
523                 mCurrentBrightness = brightnessState;
524                 mCallback.dispatchRequestedBrightnessChanged(mCurrentBrightness);
525             }
526             return runnable;
527         }
528 
529         @Override
configureSurfaceLocked(SurfaceControl.Transaction t)530         public void configureSurfaceLocked(SurfaceControl.Transaction t) {
531             if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) {
532                 setSurfaceLocked(t, mSurface);
533                 mPendingChanges &= ~PENDING_SURFACE_CHANGE;
534             }
535         }
536 
537         @Override
configureDisplaySizeLocked(SurfaceControl.Transaction t)538         public void configureDisplaySizeLocked(SurfaceControl.Transaction t) {
539             if ((mPendingChanges & PENDING_RESIZE) != 0) {
540                 setDisplaySizeLocked(t, mWidth, mHeight);
541                 mPendingChanges &= ~PENDING_RESIZE;
542             }
543         }
544 
545         @Override
shouldOnlyMirror()546         public boolean shouldOnlyMirror() {
547             return mProjection != null || ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0);
548         }
549 
setSurfaceLocked(Surface surface)550         public void setSurfaceLocked(Surface surface) {
551             if (!mStopped && mSurface != surface) {
552                 if (mDisplayState == Display.STATE_ON
553                         && ((mSurface == null) != (surface == null))) {
554                     mInfo = null;
555                     sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
556                 }
557                 sendTraversalRequestLocked();
558                 mSurface = surface;
559                 mPendingChanges |= PENDING_SURFACE_CHANGE;
560             }
561         }
562 
resizeLocked(int width, int height, int densityDpi)563         public void resizeLocked(int width, int height, int densityDpi) {
564             if (mWidth != width || mHeight != height || mDensityDpi != densityDpi) {
565                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
566                 sendTraversalRequestLocked();
567                 mWidth = width;
568                 mHeight = height;
569                 mMode = createMode(width, height, getRefreshRate());
570                 mDensityDpi = densityDpi;
571                 mInfo = null;
572                 mPendingChanges |= PENDING_RESIZE;
573             }
574         }
575 
stopLocked()576         public void stopLocked() {
577             Slog.d(TAG, "Virtual Display: stopping device " + mName);
578             setSurfaceLocked(null);
579             mStopped = true;
580         }
581 
582         @Override
dumpLocked(PrintWriter pw)583         public void dumpLocked(PrintWriter pw) {
584             super.dumpLocked(pw);
585             pw.println("mFlags=" + mFlags);
586             pw.println("mDisplayState=" + Display.stateToString(mDisplayState));
587             pw.println("mStopped=" + mStopped);
588             pw.println("mDisplayIdToMirror=" + mDisplayIdToMirror);
589             pw.println("mWindowManagerMirroring=" + mIsWindowManagerMirroring);
590             pw.println("mRequestedRefreshRate=" + mRequestedRefreshRate);
591         }
592 
593         @Override
getDisplayDeviceInfoLocked()594         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
595             if (mInfo == null) {
596                 mInfo = new DisplayDeviceInfo();
597                 mInfo.name = mName;
598                 mInfo.uniqueId = getUniqueId();
599                 mInfo.width = mWidth;
600                 mInfo.height = mHeight;
601                 mInfo.modeId = mMode.getModeId();
602                 mInfo.renderFrameRate = mMode.getRefreshRate();
603                 mInfo.defaultModeId = mMode.getModeId();
604                 mInfo.supportedModes = new Display.Mode[] { mMode };
605                 mInfo.densityDpi = mDensityDpi;
606                 mInfo.xDpi = mDensityDpi;
607                 mInfo.yDpi = mDensityDpi;
608                 mInfo.presentationDeadlineNanos = 1000000000L / (int) getRefreshRate(); // 1 frame
609                 mInfo.flags = 0;
610                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
611                     mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
612                 }
613                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0) {
614                     mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
615                 }
616                 if (mNeverBlank) {
617                     mInfo.flags |= DisplayDeviceInfo.FLAG_NEVER_BLANK;
618                 }
619                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
620                     mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
621                 }
622                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) {
623                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEVICE_DISPLAY_GROUP;
624                 }
625                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
626                     mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
627                 }
628                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) {
629                     mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
630 
631                     if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
632                         // For demonstration purposes, allow rotation of the external display.
633                         // In the future we might allow the user to configure this directly.
634                         if ("portrait".equals(SystemProperties.get(
635                                 "persist.demo.remoterotation"))) {
636                             mInfo.rotation = Surface.ROTATION_270;
637                         }
638                     }
639                 }
640                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
641                     mInfo.flags |= DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
642                 }
643                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT) != 0) {
644                     mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
645                 }
646                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL) != 0) {
647                     mInfo.flags |= DisplayDeviceInfo.FLAG_DESTROY_CONTENT_ON_REMOVAL;
648                 }
649                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) {
650                     mInfo.flags |= DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
651                 }
652                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
653                     mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
654                 }
655                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0) {
656                     mInfo.flags |= DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED;
657                 }
658                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
659                     mInfo.flags |= DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED;
660                 }
661                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_FOCUS) != 0) {
662                     mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_FOCUS;
663                 }
664                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED) != 0) {
665                     mInfo.flags |= DisplayDeviceInfo.FLAG_STEAL_TOP_FOCUS_DISABLED;
666                 }
667 
668                 mInfo.type = Display.TYPE_VIRTUAL;
669                 mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ?
670                         DisplayDeviceInfo.TOUCH_NONE : DisplayDeviceInfo.TOUCH_VIRTUAL;
671 
672                 if (mSurface == null) {
673                     mInfo.state = Display.STATE_OFF;
674                 } else {
675                     mInfo.state = mDisplayState;
676                 }
677 
678                 mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN;
679                 mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX;
680                 mInfo.brightnessDefault = mDefaultBrightness;
681                 mInfo.brightnessDim = mDimBrightness;
682 
683                 mInfo.ownerUid = mOwnerUid;
684                 mInfo.ownerPackageName = mOwnerPackageName;
685 
686                 mInfo.displayShape =
687                         DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
688                 mInfo.displayCutout = mDisplayCutout;
689             }
690             return mInfo;
691         }
692 
getRefreshRate()693         private float getRefreshRate() {
694             return (mRequestedRefreshRate != 0.0f) ? mRequestedRefreshRate : REFRESH_RATE;
695         }
696     }
697 
698     private static class Callback extends Handler {
699         private static final int MSG_ON_DISPLAY_PAUSED = 0;
700         private static final int MSG_ON_DISPLAY_RESUMED = 1;
701         private static final int MSG_ON_DISPLAY_STOPPED = 2;
702         private static final int MSG_ON_REQUESTED_BRIGHTNESS_CHANGED = 3;
703 
704         private final IVirtualDisplayCallback mCallback;
705         private final IBrightnessListener mBrightnessListener;
706 
Callback(IVirtualDisplayCallback callback, IBrightnessListener brightnessListener, Handler handler)707         Callback(IVirtualDisplayCallback callback, IBrightnessListener brightnessListener,
708                 Handler handler) {
709             super(handler.getLooper());
710             mCallback = callback;
711             mBrightnessListener = brightnessListener;
712         }
713 
714         @Override
handleMessage(Message msg)715         public void handleMessage(Message msg) {
716             try {
717                 switch (msg.what) {
718                     case MSG_ON_DISPLAY_PAUSED:
719                         mCallback.onPaused();
720                         break;
721                     case MSG_ON_DISPLAY_RESUMED:
722                         mCallback.onResumed();
723                         break;
724                     case MSG_ON_DISPLAY_STOPPED:
725                         mCallback.onStopped();
726                         break;
727                     case MSG_ON_REQUESTED_BRIGHTNESS_CHANGED:
728                         if (mBrightnessListener != null) {
729                             mBrightnessListener.onBrightnessChanged((Float) msg.obj);
730                         }
731                         break;
732                 }
733             } catch (RemoteException e) {
734                 Slog.w(TAG, "Failed to notify listener of virtual display event.", e);
735             }
736         }
737 
dispatchDisplayPaused()738         public void dispatchDisplayPaused() {
739             sendEmptyMessage(MSG_ON_DISPLAY_PAUSED);
740         }
741 
dispatchDisplayResumed()742         public void dispatchDisplayResumed() {
743             sendEmptyMessage(MSG_ON_DISPLAY_RESUMED);
744         }
745 
dispatchRequestedBrightnessChanged(float brightness)746         public void dispatchRequestedBrightnessChanged(float brightness) {
747             Message msg = obtainMessage(MSG_ON_REQUESTED_BRIGHTNESS_CHANGED, brightness);
748             sendMessage(msg);
749         }
750 
dispatchDisplayStopped()751         public void dispatchDisplayStopped() {
752             sendEmptyMessage(MSG_ON_DISPLAY_STOPPED);
753         }
754     }
755 
756     private final class MediaProjectionCallback extends IMediaProjectionCallback.Stub {
757         private IBinder mAppToken;
MediaProjectionCallback(IBinder appToken)758         public MediaProjectionCallback(IBinder appToken) {
759             mAppToken = appToken;
760         }
761 
762         @Override
onStop()763         public void onStop() {
764             synchronized (getSyncRoot()) {
765                 handleMediaProjectionStoppedLocked(mAppToken);
766             }
767         }
768 
769         @Override
onCapturedContentResize(int width, int height)770         public void onCapturedContentResize(int width, int height) {
771             // Do nothing when we tell the client that the content is resized - it is up to them
772             // to decide to update the VirtualDisplay and Surface.
773             // We could only update the VirtualDisplay size, anyway (which the client wouldn't
774             // expect), and there will still be letterboxing on the output content since the
775             // Surface and VirtualDisplay would then have different aspect ratios.
776         }
777 
778         @Override
onCapturedContentVisibilityChanged(boolean isVisible)779         public void onCapturedContentVisibilityChanged(boolean isVisible) {
780             // Do nothing when we tell the client that the content has a visibility change - it is
781             // up to them to decide to pause recording, and update their own UI, depending on their
782             // use case.
783         }
784     }
785 
786     @VisibleForTesting
787     public interface SurfaceControlDisplayFactory {
788         /**
789          * Create a virtual display in SurfaceFlinger.
790          *
791          * @param name The name of the display.
792          * @param secure Whether this display is secure.
793          * @param optimizeForPower Whether SurfaceFlinger should optimize for power (instead of
794          *                         performance). Such displays will depend on another display for
795          *                         it to be shown and rendered, and that display will optimize for
796          *                         performance when it is on.
797          * @param uniqueId The unique ID for the display.
798          * @param requestedRefreshRate
799          *     The refresh rate, frames per second, to request on the virtual display.
800          *     It should be a divisor of refresh rate of the leader physical display
801          *     that drives VSYNC, e.g. 30/60fps on 120fps display. If an arbitrary refresh
802          *     rate is specified, SurfaceFlinger rounds up or down to match a divisor of
803          *     the refresh rate of the leader physical display.
804          * @return The token reference for the display in SurfaceFlinger.
805          */
createDisplay(String name, boolean secure, boolean optimizeForPower, String uniqueId, float requestedRefreshRate)806         IBinder createDisplay(String name, boolean secure, boolean optimizeForPower,
807                 String uniqueId, float requestedRefreshRate);
808 
809         /**
810          * Destroy a display in SurfaceFlinger.
811          *
812          * @param displayToken The display token for the display to be destroyed.
813          */
destroyDisplay(IBinder displayToken)814         void destroyDisplay(IBinder displayToken);
815 
816         /**
817          * Set the display power mode in SurfaceFlinger.
818          *
819          * @param displayToken The display token for the display.
820          * @param mode the SurfaceControl power mode, e.g. {@link SurfaceControl#POWER_MODE_OFF}.
821          */
setDisplayPowerMode(IBinder displayToken, int mode)822         void setDisplayPowerMode(IBinder displayToken, int mode);
823     }
824 }
825