blob: 9d0fde5f2027f1ea09e24220e386fdb16f47afd6 [file] [log] [blame]
Jeff Browna506a6e2013-06-04 00:02:38 -07001/*
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
17package com.android.server.display;
18
19import android.content.Context;
Jeff Brown7d00aff2013-08-02 19:03:49 -070020import android.hardware.display.DisplayManager;
Michael Wright75ee9fc2014-09-01 19:55:22 -070021import android.hardware.display.IVirtualDisplayCallback;
Michael Wrightc39d47a2014-07-08 18:07:36 -070022import android.media.projection.IMediaProjection;
23import android.media.projection.IMediaProjectionCallback;
Jeff Browna506a6e2013-06-04 00:02:38 -070024import android.os.Handler;
25import android.os.IBinder;
Chong Zhangae6119ff2014-11-11 18:54:39 -080026import android.os.SystemProperties;
Jeff Browna506a6e2013-06-04 00:02:38 -070027import android.os.IBinder.DeathRecipient;
Michael Wrightc39d47a2014-07-08 18:07:36 -070028import android.os.Message;
Jeff Browna506a6e2013-06-04 00:02:38 -070029import android.os.RemoteException;
30import android.util.ArrayMap;
31import android.util.Slog;
32import android.view.Display;
33import android.view.Surface;
34import android.view.SurfaceControl;
35
Michael Wrightc39d47a2014-07-08 18:07:36 -070036import java.io.PrintWriter;
Wale Ogunwale361ca212014-11-20 11:42:38 -080037import java.util.Iterator;
Michael Wrightc39d47a2014-07-08 18:07:36 -070038
Jeff Browna506a6e2013-06-04 00:02:38 -070039/**
40 * A display adapter that provides virtual displays on behalf of applications.
41 * <p>
42 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
43 * </p>
44 */
45final class VirtualDisplayAdapter extends DisplayAdapter {
46 static final String TAG = "VirtualDisplayAdapter";
47 static final boolean DEBUG = false;
48
Wale Ogunwale361ca212014-11-20 11:42:38 -080049 // Unique id prefix for virtual displays
50 private static final String UNIQUE_ID_PREFIX = "virtual:";
51
Jeff Browna506a6e2013-06-04 00:02:38 -070052 private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices =
53 new ArrayMap<IBinder, VirtualDisplayDevice>();
Michael Wrightc39d47a2014-07-08 18:07:36 -070054 private Handler mHandler;
Jeff Browna506a6e2013-06-04 00:02:38 -070055
56 // Called with SyncRoot lock held.
57 public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
58 Context context, Handler handler, Listener listener) {
59 super(syncRoot, context, handler, listener, TAG);
Michael Wrightc39d47a2014-07-08 18:07:36 -070060 mHandler = handler;
Jeff Browna506a6e2013-06-04 00:02:38 -070061 }
62
Michael Wright75ee9fc2014-09-01 19:55:22 -070063 public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
Michael Wrightc39d47a2014-07-08 18:07:36 -070064 IMediaProjection projection, int ownerUid, String ownerPackageName,
Jeff Brown7d00aff2013-08-02 19:03:49 -070065 String name, int width, int height, int densityDpi, Surface surface, int flags) {
66 boolean secure = (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
Michael Wright75ee9fc2014-09-01 19:55:22 -070067 IBinder appToken = callback.asBinder();
Jeff Brown7d00aff2013-08-02 19:03:49 -070068 IBinder displayToken = SurfaceControl.createDisplay(name, secure);
Wale Ogunwale361ca212014-11-20 11:42:38 -080069 final String baseUniqueId =
70 UNIQUE_ID_PREFIX + ownerPackageName + "," + ownerUid + "," + name + ",";
71 final int uniqueIndex = getNextUniqueIndex(baseUniqueId);
Jeff Browna506a6e2013-06-04 00:02:38 -070072 VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
Michael Wrightc39d47a2014-07-08 18:07:36 -070073 ownerUid, ownerPackageName, name, width, height, densityDpi, surface, flags,
Wale Ogunwale361ca212014-11-20 11:42:38 -080074 new Callback(callback, mHandler), baseUniqueId + uniqueIndex, uniqueIndex);
Michael Wrightc39d47a2014-07-08 18:07:36 -070075
76 mVirtualDisplayDevices.put(appToken, device);
Jeff Browna506a6e2013-06-04 00:02:38 -070077
78 try {
Michael Wrightc39d47a2014-07-08 18:07:36 -070079 if (projection != null) {
Michael Wrightcde5bb42014-09-08 13:26:34 -070080 projection.registerCallback(new MediaProjectionCallback(appToken));
Michael Wrightc39d47a2014-07-08 18:07:36 -070081 }
Jeff Browna506a6e2013-06-04 00:02:38 -070082 appToken.linkToDeath(device, 0);
83 } catch (RemoteException ex) {
Michael Wrightc39d47a2014-07-08 18:07:36 -070084 mVirtualDisplayDevices.remove(appToken);
Michael Wrightd1a5fae2015-05-05 14:16:35 +010085 device.destroyLocked(false);
Jeff Browna506a6e2013-06-04 00:02:38 -070086 return null;
87 }
88
Jeff Browna506a6e2013-06-04 00:02:38 -070089 // Return the display device without actually sending the event indicating
90 // that it was added. The caller will handle it.
91 return device;
92 }
93
Michael Wright01e840f2014-06-26 16:03:25 -070094 public void resizeVirtualDisplayLocked(IBinder appToken,
95 int width, int height, int densityDpi) {
96 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
97 if (device != null) {
98 device.resizeLocked(width, height, densityDpi);
99 }
100 }
101
102
Jeff Brown92207df2014-04-16 13:16:07 -0700103 public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) {
104 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
105 if (device != null) {
106 device.setSurfaceLocked(surface);
107 }
108 }
109
Jeff Browna506a6e2013-06-04 00:02:38 -0700110 public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) {
111 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
112 if (device != null) {
Michael Wrightd1a5fae2015-05-05 14:16:35 +0100113 device.destroyLocked(true);
Jeff Browna506a6e2013-06-04 00:02:38 -0700114 appToken.unlinkToDeath(device, 0);
115 }
116
117 // Return the display device that was removed without actually sending the
118 // event indicating that it was removed. The caller will handle it.
119 return device;
120 }
121
Wale Ogunwale361ca212014-11-20 11:42:38 -0800122 /**
123 * Returns the next unique index for the uniqueIdPrefix
124 */
125 private int getNextUniqueIndex(String uniqueIdPrefix) {
126 if (mVirtualDisplayDevices.isEmpty()) {
127 return 0;
128 }
129
130 int nextUniqueIndex = 0;
131 Iterator<VirtualDisplayDevice> it = mVirtualDisplayDevices.values().iterator();
132 while (it.hasNext()) {
133 VirtualDisplayDevice device = it.next();
134 if (device.getUniqueId().startsWith(uniqueIdPrefix)
135 && device.mUniqueIndex >= nextUniqueIndex) {
136 // Increment the next unique index to be greater than ones we have already ran
137 // across for displays that have the same unique Id prefix.
138 nextUniqueIndex = device.mUniqueIndex + 1;
139 }
140 }
141
142 return nextUniqueIndex;
143 }
144
Jeff Browna506a6e2013-06-04 00:02:38 -0700145 private void handleBinderDiedLocked(IBinder appToken) {
146 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
147 if (device != null) {
148 Slog.i(TAG, "Virtual display device released because application token died: "
149 + device.mOwnerPackageName);
Michael Wrightd1a5fae2015-05-05 14:16:35 +0100150 device.destroyLocked(false);
Jeff Browna506a6e2013-06-04 00:02:38 -0700151 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
152 }
153 }
154
Michael Wrightc39d47a2014-07-08 18:07:36 -0700155 private void handleMediaProjectionStoppedLocked(IBinder appToken) {
156 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
157 if (device != null) {
158 Slog.i(TAG, "Virtual display device released because media projection stopped: "
159 + device.mName);
160 device.stopLocked();
161 }
162 }
163
164 private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient {
Michael Wright01e840f2014-06-26 16:03:25 -0700165 private static final int PENDING_SURFACE_CHANGE = 0x01;
166 private static final int PENDING_RESIZE = 0x02;
167
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700168 private static final float REFRESH_RATE = 60.0f;
169
Jeff Browna506a6e2013-06-04 00:02:38 -0700170 private final IBinder mAppToken;
171 private final int mOwnerUid;
172 final String mOwnerPackageName;
Michael Wrightc39d47a2014-07-08 18:07:36 -0700173 final String mName;
Jeff Brown7d00aff2013-08-02 19:03:49 -0700174 private final int mFlags;
Michael Wright75ee9fc2014-09-01 19:55:22 -0700175 private final Callback mCallback;
Jeff Browna506a6e2013-06-04 00:02:38 -0700176
Michael Wright01e840f2014-06-26 16:03:25 -0700177 private int mWidth;
178 private int mHeight;
179 private int mDensityDpi;
Jeff Browna506a6e2013-06-04 00:02:38 -0700180 private Surface mSurface;
181 private DisplayDeviceInfo mInfo;
Michael Wright01e840f2014-06-26 16:03:25 -0700182 private int mDisplayState;
Michael Wrightc39d47a2014-07-08 18:07:36 -0700183 private boolean mStopped;
Michael Wright01e840f2014-06-26 16:03:25 -0700184 private int mPendingChanges;
Wale Ogunwale361ca212014-11-20 11:42:38 -0800185 private int mUniqueIndex;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700186 private Display.Mode mMode;
Jeff Browna506a6e2013-06-04 00:02:38 -0700187
Michael Wrightc39d47a2014-07-08 18:07:36 -0700188 public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
189 int ownerUid, String ownerPackageName,
190 String name, int width, int height, int densityDpi, Surface surface, int flags,
Wale Ogunwale361ca212014-11-20 11:42:38 -0800191 Callback callback, String uniqueId, int uniqueIndex) {
192 super(VirtualDisplayAdapter.this, displayToken, uniqueId);
Jeff Browna506a6e2013-06-04 00:02:38 -0700193 mAppToken = appToken;
194 mOwnerUid = ownerUid;
195 mOwnerPackageName = ownerPackageName;
196 mName = name;
197 mWidth = width;
198 mHeight = height;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700199 mMode = createMode(width, height, REFRESH_RATE);
Jeff Browna506a6e2013-06-04 00:02:38 -0700200 mDensityDpi = densityDpi;
201 mSurface = surface;
Jeff Brown7d00aff2013-08-02 19:03:49 -0700202 mFlags = flags;
Michael Wright75ee9fc2014-09-01 19:55:22 -0700203 mCallback = callback;
Michael Wright01e840f2014-06-26 16:03:25 -0700204 mDisplayState = Display.STATE_UNKNOWN;
205 mPendingChanges |= PENDING_SURFACE_CHANGE;
Wale Ogunwale361ca212014-11-20 11:42:38 -0800206 mUniqueIndex = uniqueIndex;
Jeff Browna506a6e2013-06-04 00:02:38 -0700207 }
208
209 @Override
210 public void binderDied() {
211 synchronized (getSyncRoot()) {
Michael Wrightd1a5fae2015-05-05 14:16:35 +0100212 handleBinderDiedLocked(mAppToken);
Jeff Browna506a6e2013-06-04 00:02:38 -0700213 }
214 }
215
Michael Wrightd1a5fae2015-05-05 14:16:35 +0100216 public void destroyLocked(boolean binderAlive) {
Jesse Hall6a6bc212013-08-08 12:15:03 -0700217 if (mSurface != null) {
218 mSurface.release();
219 mSurface = null;
220 }
221 SurfaceControl.destroyDisplay(getDisplayTokenLocked());
Michael Wrightd1a5fae2015-05-05 14:16:35 +0100222 if (binderAlive) {
223 mCallback.dispatchDisplayStopped();
224 }
Michael Wrightc39d47a2014-07-08 18:07:36 -0700225 }
226
227 @Override
Michael Wright1c9977b2016-07-12 13:30:10 -0700228 public boolean hasStableUniqueId() {
229 return false;
230 }
231
232 @Override
Jeff Brown5d6443b2015-04-10 20:15:01 -0700233 public Runnable requestDisplayStateLocked(int state, int brightness) {
Michael Wright01e840f2014-06-26 16:03:25 -0700234 if (state != mDisplayState) {
235 mDisplayState = state;
Michael Wrightc39d47a2014-07-08 18:07:36 -0700236 if (state == Display.STATE_OFF) {
Michael Wright75ee9fc2014-09-01 19:55:22 -0700237 mCallback.dispatchDisplayPaused();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700238 } else {
Michael Wright75ee9fc2014-09-01 19:55:22 -0700239 mCallback.dispatchDisplayResumed();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700240 }
241 }
Jeff Browne75926d2014-09-18 15:24:49 -0700242 return null;
Jeff Browna506a6e2013-06-04 00:02:38 -0700243 }
244
245 @Override
246 public void performTraversalInTransactionLocked() {
Michael Wright01e840f2014-06-26 16:03:25 -0700247 if ((mPendingChanges & PENDING_RESIZE) != 0) {
248 SurfaceControl.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
249 }
250 if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) {
251 setSurfaceInTransactionLocked(mSurface);
252 }
253 mPendingChanges = 0;
Jeff Browna506a6e2013-06-04 00:02:38 -0700254 }
255
Jeff Brown92207df2014-04-16 13:16:07 -0700256 public void setSurfaceLocked(Surface surface) {
Michael Wrightc39d47a2014-07-08 18:07:36 -0700257 if (!mStopped && mSurface != surface) {
Jeff Brown92207df2014-04-16 13:16:07 -0700258 if ((mSurface != null) != (surface != null)) {
259 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
260 }
261 sendTraversalRequestLocked();
262 mSurface = surface;
263 mInfo = null;
Michael Wright01e840f2014-06-26 16:03:25 -0700264 mPendingChanges |= PENDING_SURFACE_CHANGE;
265 }
266 }
267
268 public void resizeLocked(int width, int height, int densityDpi) {
269 if (mWidth != width || mHeight != height || mDensityDpi != densityDpi) {
270 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
271 sendTraversalRequestLocked();
272 mWidth = width;
273 mHeight = height;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700274 mMode = createMode(width, height, REFRESH_RATE);
Michael Wright01e840f2014-06-26 16:03:25 -0700275 mDensityDpi = densityDpi;
276 mInfo = null;
277 mPendingChanges |= PENDING_RESIZE;
Jeff Brown92207df2014-04-16 13:16:07 -0700278 }
279 }
280
Michael Wrightc39d47a2014-07-08 18:07:36 -0700281 public void stopLocked() {
282 setSurfaceLocked(null);
283 mStopped = true;
284 }
285
286 @Override
287 public void dumpLocked(PrintWriter pw) {
288 super.dumpLocked(pw);
289 pw.println("mFlags=" + mFlags);
Michael Wright01e840f2014-06-26 16:03:25 -0700290 pw.println("mDisplayState=" + Display.stateToString(mDisplayState));
Michael Wrightc39d47a2014-07-08 18:07:36 -0700291 pw.println("mStopped=" + mStopped);
292 }
293
294
Jeff Browna506a6e2013-06-04 00:02:38 -0700295 @Override
296 public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
297 if (mInfo == null) {
298 mInfo = new DisplayDeviceInfo();
299 mInfo.name = mName;
Wale Ogunwale361ca212014-11-20 11:42:38 -0800300 mInfo.uniqueId = getUniqueId();
Jeff Browna506a6e2013-06-04 00:02:38 -0700301 mInfo.width = mWidth;
302 mInfo.height = mHeight;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700303 mInfo.modeId = mMode.getModeId();
304 mInfo.defaultModeId = mMode.getModeId();
305 mInfo.supportedModes = new Display.Mode[] { mMode };
Jeff Browna506a6e2013-06-04 00:02:38 -0700306 mInfo.densityDpi = mDensityDpi;
307 mInfo.xDpi = mDensityDpi;
308 mInfo.yDpi = mDensityDpi;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700309 mInfo.presentationDeadlineNanos = 1000000000L / (int) REFRESH_RATE; // 1 frame
Jeff Brown7d00aff2013-08-02 19:03:49 -0700310 mInfo.flags = 0;
311 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
Michael Wright6720be42014-07-29 19:14:16 -0700312 mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
313 | DisplayDeviceInfo.FLAG_NEVER_BLANK;
314 }
keunyoung48054242014-08-12 17:50:19 -0700315 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
Michael Wright6720be42014-07-29 19:14:16 -0700316 mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK;
317 } else {
Jeff Brownd14c8c92014-01-07 18:13:09 -0800318 mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
Jeff Brown7d00aff2013-08-02 19:03:49 -0700319 }
Michael Wright6720be42014-07-29 19:14:16 -0700320
Jeff Brown7d00aff2013-08-02 19:03:49 -0700321 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
322 mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
323 }
324 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) {
325 mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
Chong Zhangae6119ff2014-11-11 18:54:39 -0800326
327 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
328 // For demonstration purposes, allow rotation of the external display.
329 // In the future we might allow the user to configure this directly.
330 if ("portrait".equals(SystemProperties.get(
331 "persist.demo.remoterotation"))) {
332 mInfo.rotation = Surface.ROTATION_270;
333 }
334 }
Jeff Brown7d00aff2013-08-02 19:03:49 -0700335 }
Jeff Browna506a6e2013-06-04 00:02:38 -0700336 mInfo.type = Display.TYPE_VIRTUAL;
337 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
Jeff Brown92207df2014-04-16 13:16:07 -0700338 mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF;
Jeff Browna506a6e2013-06-04 00:02:38 -0700339 mInfo.ownerUid = mOwnerUid;
340 mInfo.ownerPackageName = mOwnerPackageName;
341 }
342 return mInfo;
343 }
344 }
Michael Wrightc39d47a2014-07-08 18:07:36 -0700345
Michael Wright75ee9fc2014-09-01 19:55:22 -0700346 private static class Callback extends Handler {
Michael Wrightc39d47a2014-07-08 18:07:36 -0700347 private static final int MSG_ON_DISPLAY_PAUSED = 0;
348 private static final int MSG_ON_DISPLAY_RESUMED = 1;
349 private static final int MSG_ON_DISPLAY_STOPPED = 2;
350
Michael Wright75ee9fc2014-09-01 19:55:22 -0700351 private final IVirtualDisplayCallback mCallback;
Michael Wrightc39d47a2014-07-08 18:07:36 -0700352
Michael Wright75ee9fc2014-09-01 19:55:22 -0700353 public Callback(IVirtualDisplayCallback callback, Handler handler) {
Michael Wrightc39d47a2014-07-08 18:07:36 -0700354 super(handler.getLooper());
Michael Wright75ee9fc2014-09-01 19:55:22 -0700355 mCallback = callback;
Michael Wrightc39d47a2014-07-08 18:07:36 -0700356 }
357
358 @Override
359 public void handleMessage(Message msg) {
360 try {
361 switch (msg.what) {
362 case MSG_ON_DISPLAY_PAUSED:
Michael Wright75ee9fc2014-09-01 19:55:22 -0700363 mCallback.onPaused();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700364 break;
365 case MSG_ON_DISPLAY_RESUMED:
Michael Wright75ee9fc2014-09-01 19:55:22 -0700366 mCallback.onResumed();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700367 break;
368 case MSG_ON_DISPLAY_STOPPED:
Michael Wright75ee9fc2014-09-01 19:55:22 -0700369 mCallback.onStopped();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700370 break;
371 }
372 } catch (RemoteException e) {
373 Slog.w(TAG, "Failed to notify listener of virtual display event.", e);
374 }
375 }
376
377 public void dispatchDisplayPaused() {
378 sendEmptyMessage(MSG_ON_DISPLAY_PAUSED);
379 }
380
381 public void dispatchDisplayResumed() {
382 sendEmptyMessage(MSG_ON_DISPLAY_RESUMED);
383 }
384
385 public void dispatchDisplayStopped() {
386 sendEmptyMessage(MSG_ON_DISPLAY_STOPPED);
387 }
388 }
389
390 private final class MediaProjectionCallback extends IMediaProjectionCallback.Stub {
391 private IBinder mAppToken;
392 public MediaProjectionCallback(IBinder appToken) {
393 mAppToken = appToken;
394 }
395
396 @Override
397 public void onStop() {
398 synchronized (getSyncRoot()) {
399 handleMediaProjectionStoppedLocked(mAppToken);
400 }
401 }
402 }
Jeff Browna506a6e2013-06-04 00:02:38 -0700403}