blob: f6399a329a90339fbcffa6b6d7f9f590a75a9acb [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;
26import android.os.IBinder.DeathRecipient;
Michael Wrightc39d47a2014-07-08 18:07:36 -070027import android.os.Message;
Jeff Browna506a6e2013-06-04 00:02:38 -070028import android.os.RemoteException;
29import android.util.ArrayMap;
30import android.util.Slog;
31import android.view.Display;
32import android.view.Surface;
33import android.view.SurfaceControl;
34
Michael Wrightc39d47a2014-07-08 18:07:36 -070035import java.io.PrintWriter;
36
Jeff Browna506a6e2013-06-04 00:02:38 -070037/**
38 * A display adapter that provides virtual displays on behalf of applications.
39 * <p>
40 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
41 * </p>
42 */
43final class VirtualDisplayAdapter extends DisplayAdapter {
44 static final String TAG = "VirtualDisplayAdapter";
45 static final boolean DEBUG = false;
46
47 private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices =
48 new ArrayMap<IBinder, VirtualDisplayDevice>();
Michael Wrightc39d47a2014-07-08 18:07:36 -070049 private Handler mHandler;
Jeff Browna506a6e2013-06-04 00:02:38 -070050
51 // Called with SyncRoot lock held.
52 public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
53 Context context, Handler handler, Listener listener) {
54 super(syncRoot, context, handler, listener, TAG);
Michael Wrightc39d47a2014-07-08 18:07:36 -070055 mHandler = handler;
Jeff Browna506a6e2013-06-04 00:02:38 -070056 }
57
Michael Wright75ee9fc2014-09-01 19:55:22 -070058 public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
Michael Wrightc39d47a2014-07-08 18:07:36 -070059 IMediaProjection projection, int ownerUid, String ownerPackageName,
Jeff Brown7d00aff2013-08-02 19:03:49 -070060 String name, int width, int height, int densityDpi, Surface surface, int flags) {
61 boolean secure = (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
Michael Wright75ee9fc2014-09-01 19:55:22 -070062 IBinder appToken = callback.asBinder();
Jeff Brown7d00aff2013-08-02 19:03:49 -070063 IBinder displayToken = SurfaceControl.createDisplay(name, secure);
Jeff Browna506a6e2013-06-04 00:02:38 -070064 VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
Michael Wrightc39d47a2014-07-08 18:07:36 -070065 ownerUid, ownerPackageName, name, width, height, densityDpi, surface, flags,
Michael Wright75ee9fc2014-09-01 19:55:22 -070066 new Callback(callback, mHandler));
Michael Wrightc39d47a2014-07-08 18:07:36 -070067
68 mVirtualDisplayDevices.put(appToken, device);
Jeff Browna506a6e2013-06-04 00:02:38 -070069
70 try {
Michael Wrightc39d47a2014-07-08 18:07:36 -070071 if (projection != null) {
72 projection.addCallback(new MediaProjectionCallback(appToken));
73 }
Jeff Browna506a6e2013-06-04 00:02:38 -070074 appToken.linkToDeath(device, 0);
75 } catch (RemoteException ex) {
Michael Wrightc39d47a2014-07-08 18:07:36 -070076 mVirtualDisplayDevices.remove(appToken);
Jesse Hall6a6bc212013-08-08 12:15:03 -070077 device.destroyLocked();
Jeff Browna506a6e2013-06-04 00:02:38 -070078 return null;
79 }
80
Jeff Browna506a6e2013-06-04 00:02:38 -070081 // Return the display device without actually sending the event indicating
82 // that it was added. The caller will handle it.
83 return device;
84 }
85
Michael Wright01e840f2014-06-26 16:03:25 -070086 public void resizeVirtualDisplayLocked(IBinder appToken,
87 int width, int height, int densityDpi) {
88 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
89 if (device != null) {
90 device.resizeLocked(width, height, densityDpi);
91 }
92 }
93
94
Jeff Brown92207df2014-04-16 13:16:07 -070095 public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) {
96 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
97 if (device != null) {
98 device.setSurfaceLocked(surface);
99 }
100 }
101
Jeff Browna506a6e2013-06-04 00:02:38 -0700102 public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) {
103 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
104 if (device != null) {
Jesse Hall6a6bc212013-08-08 12:15:03 -0700105 device.destroyLocked();
Jeff Browna506a6e2013-06-04 00:02:38 -0700106 appToken.unlinkToDeath(device, 0);
107 }
108
109 // Return the display device that was removed without actually sending the
110 // event indicating that it was removed. The caller will handle it.
111 return device;
112 }
113
114 private void handleBinderDiedLocked(IBinder appToken) {
115 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
116 if (device != null) {
117 Slog.i(TAG, "Virtual display device released because application token died: "
118 + device.mOwnerPackageName);
Jesse Hall6a6bc212013-08-08 12:15:03 -0700119 device.destroyLocked();
Jeff Browna506a6e2013-06-04 00:02:38 -0700120 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
121 }
122 }
123
Michael Wrightc39d47a2014-07-08 18:07:36 -0700124 private void handleMediaProjectionStoppedLocked(IBinder appToken) {
125 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
126 if (device != null) {
127 Slog.i(TAG, "Virtual display device released because media projection stopped: "
128 + device.mName);
129 device.stopLocked();
130 }
131 }
132
133 private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient {
Michael Wright01e840f2014-06-26 16:03:25 -0700134 private static final int PENDING_SURFACE_CHANGE = 0x01;
135 private static final int PENDING_RESIZE = 0x02;
136
Jeff Browna506a6e2013-06-04 00:02:38 -0700137 private final IBinder mAppToken;
138 private final int mOwnerUid;
139 final String mOwnerPackageName;
Michael Wrightc39d47a2014-07-08 18:07:36 -0700140 final String mName;
Jeff Brown7d00aff2013-08-02 19:03:49 -0700141 private final int mFlags;
Michael Wright75ee9fc2014-09-01 19:55:22 -0700142 private final Callback mCallback;
Jeff Browna506a6e2013-06-04 00:02:38 -0700143
Michael Wright01e840f2014-06-26 16:03:25 -0700144 private int mWidth;
145 private int mHeight;
146 private int mDensityDpi;
Jeff Browna506a6e2013-06-04 00:02:38 -0700147 private Surface mSurface;
148 private DisplayDeviceInfo mInfo;
Michael Wright01e840f2014-06-26 16:03:25 -0700149 private int mDisplayState;
Michael Wrightc39d47a2014-07-08 18:07:36 -0700150 private boolean mStopped;
Michael Wright01e840f2014-06-26 16:03:25 -0700151 private int mPendingChanges;
Jeff Browna506a6e2013-06-04 00:02:38 -0700152
Michael Wrightc39d47a2014-07-08 18:07:36 -0700153 public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
154 int ownerUid, String ownerPackageName,
155 String name, int width, int height, int densityDpi, Surface surface, int flags,
Michael Wright75ee9fc2014-09-01 19:55:22 -0700156 Callback callback) {
Jeff Browna506a6e2013-06-04 00:02:38 -0700157 super(VirtualDisplayAdapter.this, displayToken);
158 mAppToken = appToken;
159 mOwnerUid = ownerUid;
160 mOwnerPackageName = ownerPackageName;
161 mName = name;
162 mWidth = width;
163 mHeight = height;
164 mDensityDpi = densityDpi;
165 mSurface = surface;
Jeff Brown7d00aff2013-08-02 19:03:49 -0700166 mFlags = flags;
Michael Wright75ee9fc2014-09-01 19:55:22 -0700167 mCallback = callback;
Michael Wright01e840f2014-06-26 16:03:25 -0700168 mDisplayState = Display.STATE_UNKNOWN;
169 mPendingChanges |= PENDING_SURFACE_CHANGE;
Jeff Browna506a6e2013-06-04 00:02:38 -0700170 }
171
172 @Override
173 public void binderDied() {
174 synchronized (getSyncRoot()) {
Jesse Hall6a6bc212013-08-08 12:15:03 -0700175 if (mSurface != null) {
Jeff Browna506a6e2013-06-04 00:02:38 -0700176 handleBinderDiedLocked(mAppToken);
177 }
178 }
179 }
180
Jesse Hall6a6bc212013-08-08 12:15:03 -0700181 public void destroyLocked() {
182 if (mSurface != null) {
183 mSurface.release();
184 mSurface = null;
185 }
186 SurfaceControl.destroyDisplay(getDisplayTokenLocked());
Michael Wright75ee9fc2014-09-01 19:55:22 -0700187 mCallback.dispatchDisplayStopped();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700188 }
189
190 @Override
191 public void requestDisplayStateLocked(int state) {
Michael Wright01e840f2014-06-26 16:03:25 -0700192 if (state != mDisplayState) {
193 mDisplayState = state;
Michael Wrightc39d47a2014-07-08 18:07:36 -0700194 if (state == Display.STATE_OFF) {
Michael Wright75ee9fc2014-09-01 19:55:22 -0700195 mCallback.dispatchDisplayPaused();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700196 } else {
Michael Wright75ee9fc2014-09-01 19:55:22 -0700197 mCallback.dispatchDisplayResumed();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700198 }
199 }
Jeff Browna506a6e2013-06-04 00:02:38 -0700200 }
201
202 @Override
203 public void performTraversalInTransactionLocked() {
Michael Wright01e840f2014-06-26 16:03:25 -0700204 if ((mPendingChanges & PENDING_RESIZE) != 0) {
205 SurfaceControl.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
206 }
207 if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) {
208 setSurfaceInTransactionLocked(mSurface);
209 }
210 mPendingChanges = 0;
Jeff Browna506a6e2013-06-04 00:02:38 -0700211 }
212
Jeff Brown92207df2014-04-16 13:16:07 -0700213 public void setSurfaceLocked(Surface surface) {
Michael Wrightc39d47a2014-07-08 18:07:36 -0700214 if (!mStopped && mSurface != surface) {
Jeff Brown92207df2014-04-16 13:16:07 -0700215 if ((mSurface != null) != (surface != null)) {
216 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
217 }
218 sendTraversalRequestLocked();
219 mSurface = surface;
220 mInfo = null;
Michael Wright01e840f2014-06-26 16:03:25 -0700221 mPendingChanges |= PENDING_SURFACE_CHANGE;
222 }
223 }
224
225 public void resizeLocked(int width, int height, int densityDpi) {
226 if (mWidth != width || mHeight != height || mDensityDpi != densityDpi) {
227 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
228 sendTraversalRequestLocked();
229 mWidth = width;
230 mHeight = height;
231 mDensityDpi = densityDpi;
232 mInfo = null;
233 mPendingChanges |= PENDING_RESIZE;
Jeff Brown92207df2014-04-16 13:16:07 -0700234 }
235 }
236
Michael Wrightc39d47a2014-07-08 18:07:36 -0700237 public void stopLocked() {
238 setSurfaceLocked(null);
239 mStopped = true;
240 }
241
242 @Override
243 public void dumpLocked(PrintWriter pw) {
244 super.dumpLocked(pw);
245 pw.println("mFlags=" + mFlags);
Michael Wright01e840f2014-06-26 16:03:25 -0700246 pw.println("mDisplayState=" + Display.stateToString(mDisplayState));
Michael Wrightc39d47a2014-07-08 18:07:36 -0700247 pw.println("mStopped=" + mStopped);
248 }
249
250
Jeff Browna506a6e2013-06-04 00:02:38 -0700251 @Override
252 public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
253 if (mInfo == null) {
254 mInfo = new DisplayDeviceInfo();
255 mInfo.name = mName;
256 mInfo.width = mWidth;
257 mInfo.height = mHeight;
258 mInfo.refreshRate = 60;
259 mInfo.densityDpi = mDensityDpi;
260 mInfo.xDpi = mDensityDpi;
261 mInfo.yDpi = mDensityDpi;
Andy McFaddene8b1aeb2014-06-13 14:05:40 -0700262 mInfo.presentationDeadlineNanos = 1000000000L / (int) mInfo.refreshRate; // 1 frame
Jeff Brown7d00aff2013-08-02 19:03:49 -0700263 mInfo.flags = 0;
264 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
Michael Wright6720be42014-07-29 19:14:16 -0700265 mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
266 | DisplayDeviceInfo.FLAG_NEVER_BLANK;
267 }
keunyoung48054242014-08-12 17:50:19 -0700268 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
Michael Wright6720be42014-07-29 19:14:16 -0700269 mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK;
270 } else {
Jeff Brownd14c8c92014-01-07 18:13:09 -0800271 mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
Jeff Brown7d00aff2013-08-02 19:03:49 -0700272 }
Michael Wright6720be42014-07-29 19:14:16 -0700273
Jeff Brown7d00aff2013-08-02 19:03:49 -0700274 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
275 mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
276 }
277 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) {
278 mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
279 }
Jeff Browna506a6e2013-06-04 00:02:38 -0700280 mInfo.type = Display.TYPE_VIRTUAL;
281 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
Jeff Brown92207df2014-04-16 13:16:07 -0700282 mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF;
Jeff Browna506a6e2013-06-04 00:02:38 -0700283 mInfo.ownerUid = mOwnerUid;
284 mInfo.ownerPackageName = mOwnerPackageName;
285 }
286 return mInfo;
287 }
288 }
Michael Wrightc39d47a2014-07-08 18:07:36 -0700289
Michael Wright75ee9fc2014-09-01 19:55:22 -0700290 private static class Callback extends Handler {
Michael Wrightc39d47a2014-07-08 18:07:36 -0700291 private static final int MSG_ON_DISPLAY_PAUSED = 0;
292 private static final int MSG_ON_DISPLAY_RESUMED = 1;
293 private static final int MSG_ON_DISPLAY_STOPPED = 2;
294
Michael Wright75ee9fc2014-09-01 19:55:22 -0700295 private final IVirtualDisplayCallback mCallback;
Michael Wrightc39d47a2014-07-08 18:07:36 -0700296
Michael Wright75ee9fc2014-09-01 19:55:22 -0700297 public Callback(IVirtualDisplayCallback callback, Handler handler) {
Michael Wrightc39d47a2014-07-08 18:07:36 -0700298 super(handler.getLooper());
Michael Wright75ee9fc2014-09-01 19:55:22 -0700299 mCallback = callback;
Michael Wrightc39d47a2014-07-08 18:07:36 -0700300 }
301
302 @Override
303 public void handleMessage(Message msg) {
304 try {
305 switch (msg.what) {
306 case MSG_ON_DISPLAY_PAUSED:
Michael Wright75ee9fc2014-09-01 19:55:22 -0700307 mCallback.onPaused();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700308 break;
309 case MSG_ON_DISPLAY_RESUMED:
Michael Wright75ee9fc2014-09-01 19:55:22 -0700310 mCallback.onResumed();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700311 break;
312 case MSG_ON_DISPLAY_STOPPED:
Michael Wright75ee9fc2014-09-01 19:55:22 -0700313 mCallback.onStopped();
Michael Wrightc39d47a2014-07-08 18:07:36 -0700314 break;
315 }
316 } catch (RemoteException e) {
317 Slog.w(TAG, "Failed to notify listener of virtual display event.", e);
318 }
319 }
320
321 public void dispatchDisplayPaused() {
322 sendEmptyMessage(MSG_ON_DISPLAY_PAUSED);
323 }
324
325 public void dispatchDisplayResumed() {
326 sendEmptyMessage(MSG_ON_DISPLAY_RESUMED);
327 }
328
329 public void dispatchDisplayStopped() {
330 sendEmptyMessage(MSG_ON_DISPLAY_STOPPED);
331 }
332 }
333
334 private final class MediaProjectionCallback extends IMediaProjectionCallback.Stub {
335 private IBinder mAppToken;
336 public MediaProjectionCallback(IBinder appToken) {
337 mAppToken = appToken;
338 }
339
340 @Override
341 public void onStop() {
342 synchronized (getSyncRoot()) {
343 handleMediaProjectionStoppedLocked(mAppToken);
344 }
345 }
346 }
Jeff Browna506a6e2013-06-04 00:02:38 -0700347}