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