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 static com.android.server.display.DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED;
37 import static com.android.server.display.DisplayDeviceInfo.FLAG_DEVICE_DISPLAY_GROUP;
38 import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
39 import static com.android.server.display.DisplayDeviceInfo.FLAG_STEAL_TOP_FOCUS_DISABLED;
40 import static com.android.server.display.DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED;
41 import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED;
42 
43 import android.annotation.Nullable;
44 import android.content.Context;
45 import android.graphics.Point;
46 import android.hardware.display.IVirtualDisplayCallback;
47 import android.hardware.display.VirtualDisplayConfig;
48 import android.media.projection.IMediaProjection;
49 import android.media.projection.IMediaProjectionCallback;
50 import android.os.Handler;
51 import android.os.IBinder;
52 import android.os.IBinder.DeathRecipient;
53 import android.os.Message;
54 import android.os.RemoteException;
55 import android.os.SystemProperties;
56 import android.util.ArrayMap;
57 import android.util.Slog;
58 import android.view.Display;
59 import android.view.DisplayShape;
60 import android.view.Surface;
61 import android.view.SurfaceControl;
62 
63 import com.android.internal.annotations.VisibleForTesting;
64 
65 import java.io.PrintWriter;
66 import java.util.Iterator;
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
75 public class VirtualDisplayAdapter extends DisplayAdapter {
76     static final String TAG = "VirtualDisplayAdapter";
77     static final boolean DEBUG = false;
78 
79     // Unique id prefix for virtual displays
80     @VisibleForTesting
81     static final String UNIQUE_ID_PREFIX = "virtual:";
82 
83     private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices =
84             new ArrayMap<IBinder, VirtualDisplayDevice>();
85     private final Handler mHandler;
86     private final SurfaceControlDisplayFactory mSurfaceControlDisplayFactory;
87 
88     // Called with SyncRoot lock held.
VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener)89     public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
90             Context context, Handler handler, Listener listener) {
91         this(syncRoot, context, handler, listener, new SurfaceControlDisplayFactory() {
92             @Override
93             public IBinder createDisplay(String name, boolean secure, float requestedRefreshRate) {
94                 return DisplayControl.createDisplay(name, secure, requestedRefreshRate);
95             }
96 
97             @Override
98             public void destroyDisplay(IBinder displayToken) {
99                 DisplayControl.destroyDisplay(displayToken);
100             }
101         });
102     }
103 
104     @VisibleForTesting
VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, SurfaceControlDisplayFactory surfaceControlDisplayFactory)105     VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
106             Context context, Handler handler, Listener listener,
107             SurfaceControlDisplayFactory surfaceControlDisplayFactory) {
108         super(syncRoot, context, handler, listener, TAG);
109         mHandler = handler;
110         mSurfaceControlDisplayFactory = surfaceControlDisplayFactory;
111     }
112 
createVirtualDisplayLocked(IVirtualDisplayCallback callback, IMediaProjection projection, int ownerUid, String ownerPackageName, Surface surface, int flags, VirtualDisplayConfig virtualDisplayConfig)113     public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
114             IMediaProjection projection, int ownerUid, String ownerPackageName, Surface surface,
115             int flags, VirtualDisplayConfig virtualDisplayConfig) {
116         String name = virtualDisplayConfig.getName();
117         boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
118         IBinder appToken = callback.asBinder();
119         IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure,
120                 virtualDisplayConfig.getRequestedRefreshRate());
121         final String baseUniqueId =
122                 UNIQUE_ID_PREFIX + ownerPackageName + "," + ownerUid + "," + name + ",";
123         final int uniqueIndex = getNextUniqueIndex(baseUniqueId);
124         String uniqueId = virtualDisplayConfig.getUniqueId();
125         if (uniqueId == null) {
126             uniqueId = baseUniqueId + uniqueIndex;
127         } else {
128             uniqueId = UNIQUE_ID_PREFIX + ownerPackageName + ":" + uniqueId;
129         }
130         MediaProjectionCallback mediaProjectionCallback =  null;
131         if (projection != null) {
132             mediaProjectionCallback = new MediaProjectionCallback(appToken);
133         }
134         VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
135                 ownerUid, ownerPackageName, surface, flags,
136                 new Callback(callback, mHandler), projection, mediaProjectionCallback,
137                 uniqueId, uniqueIndex, virtualDisplayConfig);
138 
139         mVirtualDisplayDevices.put(appToken, device);
140 
141         try {
142             if (projection != null) {
143                 projection.registerCallback(mediaProjectionCallback);
144                 Slog.d(TAG, "Virtual Display: registered media projection callback for new "
145                         + "VirtualDisplayDevice");
146             }
147             appToken.linkToDeath(device, 0);
148         } catch (RemoteException ex) {
149             Slog.e(TAG, "Virtual Display: error while setting up VirtualDisplayDevice", ex);
150             mVirtualDisplayDevices.remove(appToken);
151             device.destroyLocked(false);
152             return null;
153         }
154 
155         // Return the display device without actually sending the event indicating
156         // that it was added.  The caller will handle it.
157         return device;
158     }
159 
resizeVirtualDisplayLocked(IBinder appToken, int width, int height, int densityDpi)160     public void resizeVirtualDisplayLocked(IBinder appToken,
161             int width, int height, int densityDpi) {
162         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
163         if (device != null) {
164             Slog.v(TAG, "Resize VirtualDisplay " + device.mName + " to " + width
165                     + " " + height);
166             device.resizeLocked(width, height, densityDpi);
167         }
168     }
169 
170     @VisibleForTesting
getVirtualDisplaySurfaceLocked(IBinder appToken)171     Surface getVirtualDisplaySurfaceLocked(IBinder appToken) {
172         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
173         if (device != null) {
174             return device.getSurfaceLocked();
175         }
176         return null;
177     }
178 
setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface)179     public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) {
180         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
181         if (device != null) {
182             Slog.v(TAG, "Update surface for VirtualDisplay " + device.mName);
183             device.setSurfaceLocked(surface);
184         }
185     }
186 
setDisplayIdToMirror(IBinder appToken, int displayId)187     void setDisplayIdToMirror(IBinder appToken, int displayId) {
188         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
189         if (device != null) {
190             device.setDisplayIdToMirror(displayId);
191         }
192     }
193 
releaseVirtualDisplayLocked(IBinder appToken)194     public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) {
195         VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
196         if (device != null) {
197             Slog.v(TAG, "Release VirtualDisplay " + device.mName);
198             device.destroyLocked(true);
199             appToken.unlinkToDeath(device, 0);
200         }
201 
202         // Return the display device that was removed without actually sending the
203         // event indicating that it was removed.  The caller will handle it.
204         return device;
205     }
206 
setVirtualDisplayStateLocked(IBinder appToken, boolean isOn)207     void setVirtualDisplayStateLocked(IBinder appToken, boolean isOn) {
208         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
209         if (device != null) {
210             device.setDisplayState(isOn);
211         }
212     }
213 
214     /**
215      * Returns the next unique index for the uniqueIdPrefix
216      */
getNextUniqueIndex(String uniqueIdPrefix)217     private int getNextUniqueIndex(String uniqueIdPrefix) {
218         if (mVirtualDisplayDevices.isEmpty()) {
219             return 0;
220         }
221 
222         int nextUniqueIndex = 0;
223         Iterator<VirtualDisplayDevice> it = mVirtualDisplayDevices.values().iterator();
224         while (it.hasNext()) {
225             VirtualDisplayDevice device = it.next();
226             if (device.getUniqueId().startsWith(uniqueIdPrefix)
227                     && device.mUniqueIndex >= nextUniqueIndex) {
228                 // Increment the next unique index to be greater than ones we have already ran
229                 // across for displays that have the same unique Id prefix.
230                 nextUniqueIndex = device.mUniqueIndex + 1;
231             }
232         }
233 
234         return nextUniqueIndex;
235     }
236 
handleBinderDiedLocked(IBinder appToken)237     private void handleBinderDiedLocked(IBinder appToken) {
238         mVirtualDisplayDevices.remove(appToken);
239     }
240 
handleMediaProjectionStoppedLocked(IBinder appToken)241     private void handleMediaProjectionStoppedLocked(IBinder appToken) {
242         VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
243         if (device != null) {
244             Slog.i(TAG, "Virtual display device released because media projection stopped: "
245                     + device.mName);
246             device.stopLocked();
247         }
248     }
249 
250     private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient {
251         private static final int PENDING_SURFACE_CHANGE = 0x01;
252         private static final int PENDING_RESIZE = 0x02;
253 
254         private static final float REFRESH_RATE = 60.0f;
255 
256         private final IBinder mAppToken;
257         private final int mOwnerUid;
258         final String mOwnerPackageName;
259         final String mName;
260         private final int mFlags;
261         private final Callback mCallback;
262         @Nullable private final IMediaProjection mProjection;
263         @Nullable private final IMediaProjectionCallback mMediaProjectionCallback;
264 
265         private int mWidth;
266         private int mHeight;
267         private int mDensityDpi;
268         private float mRequestedRefreshRate;
269         private Surface mSurface;
270         private DisplayDeviceInfo mInfo;
271         private int mDisplayState;
272         private boolean mStopped;
273         private int mPendingChanges;
274         private int mUniqueIndex;
275         private Display.Mode mMode;
276         private boolean mIsDisplayOn;
277         private int mDisplayIdToMirror;
278         private boolean mIsWindowManagerMirroring;
279 
VirtualDisplayDevice(IBinder displayToken, IBinder appToken, int ownerUid, String ownerPackageName, Surface surface, int flags, Callback callback, IMediaProjection projection, IMediaProjectionCallback mediaProjectionCallback, String uniqueId, int uniqueIndex, VirtualDisplayConfig virtualDisplayConfig)280         public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
281                 int ownerUid, String ownerPackageName, Surface surface, int flags,
282                 Callback callback, IMediaProjection projection,
283                 IMediaProjectionCallback mediaProjectionCallback, String uniqueId, int uniqueIndex,
284                 VirtualDisplayConfig virtualDisplayConfig) {
285             super(VirtualDisplayAdapter.this, displayToken, uniqueId, getContext());
286             mAppToken = appToken;
287             mOwnerUid = ownerUid;
288             mOwnerPackageName = ownerPackageName;
289             mName = virtualDisplayConfig.getName();
290             mWidth = virtualDisplayConfig.getWidth();
291             mHeight = virtualDisplayConfig.getHeight();
292             mDensityDpi = virtualDisplayConfig.getDensityDpi();
293             mRequestedRefreshRate = virtualDisplayConfig.getRequestedRefreshRate();
294             mMode = createMode(mWidth, mHeight, getRefreshRate());
295             mSurface = surface;
296             mFlags = flags;
297             mCallback = callback;
298             mProjection = projection;
299             mMediaProjectionCallback = mediaProjectionCallback;
300             mDisplayState = Display.STATE_UNKNOWN;
301             mPendingChanges |= PENDING_SURFACE_CHANGE;
302             mUniqueIndex = uniqueIndex;
303             mIsDisplayOn = surface != null;
304             mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror();
305             mIsWindowManagerMirroring = virtualDisplayConfig.isWindowManagerMirroringEnabled();
306         }
307 
308         @Override
binderDied()309         public void binderDied() {
310             synchronized (getSyncRoot()) {
311                 handleBinderDiedLocked(mAppToken);
312                 Slog.i(TAG, "Virtual display device released because application token died: "
313                     + mOwnerPackageName);
314                 destroyLocked(false);
315                 if (mProjection != null && mMediaProjectionCallback != null) {
316                     try {
317                         mProjection.unregisterCallback(mMediaProjectionCallback);
318                     } catch (RemoteException e) {
319                         Slog.w(TAG, "Failed to unregister callback in binderDied", e);
320                     }
321                 }
322                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_REMOVED);
323             }
324         }
325 
destroyLocked(boolean binderAlive)326         public void destroyLocked(boolean binderAlive) {
327             if (mSurface != null) {
328                 mSurface.release();
329                 mSurface = null;
330             }
331             mSurfaceControlDisplayFactory.destroyDisplay(getDisplayTokenLocked());
332             if (mProjection != null && mMediaProjectionCallback != null) {
333                 try {
334                     mProjection.unregisterCallback(mMediaProjectionCallback);
335                 } catch (RemoteException e) {
336                     Slog.w(TAG, "Failed to unregister callback in destroy", e);
337                 }
338             }
339             if (binderAlive) {
340                 mCallback.dispatchDisplayStopped();
341             }
342         }
343 
344         @Override
getDisplayIdToMirrorLocked()345         public int getDisplayIdToMirrorLocked() {
346             return mDisplayIdToMirror;
347         }
348 
setDisplayIdToMirror(int displayIdToMirror)349         void setDisplayIdToMirror(int displayIdToMirror) {
350             if (mDisplayIdToMirror != displayIdToMirror) {
351                 mDisplayIdToMirror = displayIdToMirror;
352                 mInfo = null;
353                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
354                 sendTraversalRequestLocked();
355             }
356         }
357 
358         @Override
isWindowManagerMirroringLocked()359         public boolean isWindowManagerMirroringLocked() {
360             return mIsWindowManagerMirroring;
361         }
362 
363         @Override
setWindowManagerMirroringLocked(boolean mirroring)364         public void setWindowManagerMirroringLocked(boolean mirroring) {
365             if (mIsWindowManagerMirroring != mirroring) {
366                 mIsWindowManagerMirroring = mirroring;
367                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
368                 sendTraversalRequestLocked();
369             }
370         }
371 
372         @Override
getDisplaySurfaceDefaultSizeLocked()373         public Point getDisplaySurfaceDefaultSizeLocked() {
374             if (mSurface == null) {
375                 return null;
376             }
377             return mSurface.getDefaultSize();
378         }
379 
380         @VisibleForTesting
getSurfaceLocked()381         Surface getSurfaceLocked() {
382             return mSurface;
383         }
384 
385         @Override
hasStableUniqueId()386         public boolean hasStableUniqueId() {
387             return false;
388         }
389 
390         @Override
requestDisplayStateLocked(int state, float brightnessState, float sdrBrightnessState)391         public Runnable requestDisplayStateLocked(int state, float brightnessState,
392                 float sdrBrightnessState) {
393             if (state != mDisplayState) {
394                 mDisplayState = state;
395                 if (state == Display.STATE_OFF) {
396                     mCallback.dispatchDisplayPaused();
397                 } else {
398                     mCallback.dispatchDisplayResumed();
399                 }
400             }
401             return null;
402         }
403 
404         @Override
performTraversalLocked(SurfaceControl.Transaction t)405         public void performTraversalLocked(SurfaceControl.Transaction t) {
406             if ((mPendingChanges & PENDING_RESIZE) != 0) {
407                 t.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
408             }
409             if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) {
410                 setSurfaceLocked(t, mSurface);
411             }
412             mPendingChanges = 0;
413         }
414 
setSurfaceLocked(Surface surface)415         public void setSurfaceLocked(Surface surface) {
416             if (!mStopped && mSurface != surface) {
417                 if ((mSurface != null) != (surface != null)) {
418                     sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
419                 }
420                 sendTraversalRequestLocked();
421                 mSurface = surface;
422                 mInfo = null;
423                 mPendingChanges |= PENDING_SURFACE_CHANGE;
424             }
425         }
426 
resizeLocked(int width, int height, int densityDpi)427         public void resizeLocked(int width, int height, int densityDpi) {
428             if (mWidth != width || mHeight != height || mDensityDpi != densityDpi) {
429                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
430                 sendTraversalRequestLocked();
431                 mWidth = width;
432                 mHeight = height;
433                 mMode = createMode(width, height, getRefreshRate());
434                 mDensityDpi = densityDpi;
435                 mInfo = null;
436                 mPendingChanges |= PENDING_RESIZE;
437             }
438         }
439 
setDisplayState(boolean isOn)440         void setDisplayState(boolean isOn) {
441             if (mIsDisplayOn != isOn) {
442                 mIsDisplayOn = isOn;
443                 mInfo = null;
444                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
445             }
446         }
447 
stopLocked()448         public void stopLocked() {
449             Slog.d(TAG, "Virtual Display: stopping device " + mName);
450             setSurfaceLocked(null);
451             mStopped = true;
452         }
453 
454         @Override
dumpLocked(PrintWriter pw)455         public void dumpLocked(PrintWriter pw) {
456             super.dumpLocked(pw);
457             pw.println("mFlags=" + mFlags);
458             pw.println("mDisplayState=" + Display.stateToString(mDisplayState));
459             pw.println("mStopped=" + mStopped);
460             pw.println("mDisplayIdToMirror=" + mDisplayIdToMirror);
461             pw.println("mWindowManagerMirroring=" + mIsWindowManagerMirroring);
462             pw.println("mRequestedRefreshRate=" + mRequestedRefreshRate);
463         }
464 
465         @Override
getDisplayDeviceInfoLocked()466         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
467             if (mInfo == null) {
468                 mInfo = new DisplayDeviceInfo();
469                 mInfo.name = mName;
470                 mInfo.uniqueId = getUniqueId();
471                 mInfo.width = mWidth;
472                 mInfo.height = mHeight;
473                 mInfo.modeId = mMode.getModeId();
474                 mInfo.renderFrameRate = mMode.getRefreshRate();
475                 mInfo.defaultModeId = mMode.getModeId();
476                 mInfo.supportedModes = new Display.Mode[] { mMode };
477                 mInfo.densityDpi = mDensityDpi;
478                 mInfo.xDpi = mDensityDpi;
479                 mInfo.yDpi = mDensityDpi;
480                 mInfo.presentationDeadlineNanos = 1000000000L / (int) getRefreshRate(); // 1 frame
481                 mInfo.flags = 0;
482                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
483                     mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
484                             | DisplayDeviceInfo.FLAG_NEVER_BLANK;
485                 }
486                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
487                     mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK;
488                 } else {
489                     mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
490 
491                     if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
492                         mInfo.flags |= FLAG_OWN_DISPLAY_GROUP;
493                     }
494                 }
495                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) {
496                     mInfo.flags |= FLAG_DEVICE_DISPLAY_GROUP;
497                 }
498 
499                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
500                     mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
501                 }
502                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) {
503                     mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
504 
505                     if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
506                         // For demonstration purposes, allow rotation of the external display.
507                         // In the future we might allow the user to configure this directly.
508                         if ("portrait".equals(SystemProperties.get(
509                                 "persist.demo.remoterotation"))) {
510                             mInfo.rotation = Surface.ROTATION_270;
511                         }
512                     }
513                 }
514                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
515                     mInfo.flags |= DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
516                 }
517                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT) != 0) {
518                     mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
519                 }
520                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL) != 0) {
521                     mInfo.flags |= DisplayDeviceInfo.FLAG_DESTROY_CONTENT_ON_REMOVAL;
522                 }
523                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) {
524                     mInfo.flags |= DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
525                 }
526                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
527                     mInfo.flags |= FLAG_TRUSTED;
528                 }
529                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0) {
530                     if ((mInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0
531                             || (mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) {
532                         mInfo.flags |= FLAG_ALWAYS_UNLOCKED;
533                     } else {
534                         Slog.w(
535                                 TAG,
536                                 "Ignoring VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED as it requires"
537                                     + " VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP or"
538                                     + " VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP.");
539                     }
540                 }
541                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
542                     mInfo.flags |= FLAG_TOUCH_FEEDBACK_DISABLED;
543                 }
544                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_FOCUS) != 0) {
545                     if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
546                         mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_FOCUS;
547                     } else {
548                         Slog.w(TAG, "Ignoring VIRTUAL_DISPLAY_FLAG_OWN_FOCUS as it requires "
549                                 + "VIRTUAL_DISPLAY_FLAG_TRUSTED.");
550                     }
551                 }
552                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED) != 0) {
553                     if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0
554                             && (mFlags & VIRTUAL_DISPLAY_FLAG_OWN_FOCUS) != 0) {
555                         mInfo.flags |= FLAG_STEAL_TOP_FOCUS_DISABLED;
556                     } else {
557                         Slog.w(TAG,
558                                 "Ignoring VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED as it "
559                                         + "requires VIRTUAL_DISPLAY_FLAG_OWN_FOCUS which requires "
560                                         + "VIRTUAL_DISPLAY_FLAG_TRUSTED.");
561                     }
562                 }
563 
564                 mInfo.type = Display.TYPE_VIRTUAL;
565                 mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ?
566                         DisplayDeviceInfo.TOUCH_NONE : DisplayDeviceInfo.TOUCH_VIRTUAL;
567 
568                 mInfo.state = mIsDisplayOn ? Display.STATE_ON : Display.STATE_OFF;
569 
570                 mInfo.ownerUid = mOwnerUid;
571                 mInfo.ownerPackageName = mOwnerPackageName;
572 
573                 mInfo.displayShape =
574                         DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
575             }
576             return mInfo;
577         }
578 
getRefreshRate()579         private float getRefreshRate() {
580             return (mRequestedRefreshRate != 0.0f) ? mRequestedRefreshRate : REFRESH_RATE;
581         }
582     }
583 
584     private static class Callback extends Handler {
585         private static final int MSG_ON_DISPLAY_PAUSED = 0;
586         private static final int MSG_ON_DISPLAY_RESUMED = 1;
587         private static final int MSG_ON_DISPLAY_STOPPED = 2;
588 
589         private final IVirtualDisplayCallback mCallback;
590 
Callback(IVirtualDisplayCallback callback, Handler handler)591         public Callback(IVirtualDisplayCallback callback, Handler handler) {
592             super(handler.getLooper());
593             mCallback = callback;
594         }
595 
596         @Override
handleMessage(Message msg)597         public void handleMessage(Message msg) {
598             try {
599                 switch (msg.what) {
600                     case MSG_ON_DISPLAY_PAUSED:
601                         mCallback.onPaused();
602                         break;
603                     case MSG_ON_DISPLAY_RESUMED:
604                         mCallback.onResumed();
605                         break;
606                     case MSG_ON_DISPLAY_STOPPED:
607                         mCallback.onStopped();
608                         break;
609                 }
610             } catch (RemoteException e) {
611                 Slog.w(TAG, "Failed to notify listener of virtual display event.", e);
612             }
613         }
614 
dispatchDisplayPaused()615         public void dispatchDisplayPaused() {
616             sendEmptyMessage(MSG_ON_DISPLAY_PAUSED);
617         }
618 
dispatchDisplayResumed()619         public void dispatchDisplayResumed() {
620             sendEmptyMessage(MSG_ON_DISPLAY_RESUMED);
621         }
622 
dispatchDisplayStopped()623         public void dispatchDisplayStopped() {
624             sendEmptyMessage(MSG_ON_DISPLAY_STOPPED);
625         }
626     }
627 
628     private final class MediaProjectionCallback extends IMediaProjectionCallback.Stub {
629         private IBinder mAppToken;
MediaProjectionCallback(IBinder appToken)630         public MediaProjectionCallback(IBinder appToken) {
631             mAppToken = appToken;
632         }
633 
634         @Override
onStop()635         public void onStop() {
636             synchronized (getSyncRoot()) {
637                 handleMediaProjectionStoppedLocked(mAppToken);
638             }
639         }
640 
641         @Override
onCapturedContentResize(int width, int height)642         public void onCapturedContentResize(int width, int height) {
643             // Do nothing when we tell the client that the content is resized - it is up to them
644             // to decide to update the VirtualDisplay and Surface.
645             // We could only update the VirtualDisplay size, anyway (which the client wouldn't
646             // expect), and there will still be letterboxing on the output content since the
647             // Surface and VirtualDisplay would then have different aspect ratios.
648         }
649 
650         @Override
onCapturedContentVisibilityChanged(boolean isVisible)651         public void onCapturedContentVisibilityChanged(boolean isVisible) {
652             // Do nothing when we tell the client that the content has a visibility change - it is
653             // up to them to decide to pause recording, and update their own UI, depending on their
654             // use case.
655         }
656     }
657 
658     @VisibleForTesting
659     public interface SurfaceControlDisplayFactory {
660         /**
661          * Create a virtual display in SurfaceFlinger.
662          *
663          * @param name The name of the display
664          * @param secure Whether this display is secure.
665          * @param requestedRefreshRate
666          *     The refresh rate, frames per second, to request on the virtual display.
667          *     It should be a divisor of refresh rate of the leader physical display
668          *     that drives VSYNC, e.g. 30/60fps on 120fps display. If an arbitrary refresh
669          *     rate is specified, SurfaceFlinger rounds up or down to match a divisor of
670          *     the refresh rate of the leader physical display.
671          * @return The token reference for the display in SurfaceFlinger.
672          */
createDisplay(String name, boolean secure, float requestedRefreshRate)673         IBinder createDisplay(String name, boolean secure, float requestedRefreshRate);
674 
675         /**
676          * Destroy a display in SurfaceFlinger.
677          *
678          * @param displayToken The display token for the display to be destroyed.
679          */
destroyDisplay(IBinder displayToken)680         void destroyDisplay(IBinder displayToken);
681     }
682 }
683