VirtualDisplayAdapter.java revision c39d47a8e7c74bd539104b0efab898ef6fc43ddf
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 17package com.android.server.display; 18 19import android.content.Context; 20import android.hardware.display.DisplayManager; 21import android.hardware.display.IVirtualDisplayCallbacks; 22import android.media.projection.IMediaProjection; 23import android.media.projection.IMediaProjectionCallback; 24import android.os.Handler; 25import android.os.IBinder; 26import android.os.IBinder.DeathRecipient; 27import android.os.Message; 28import android.os.RemoteException; 29import android.util.ArrayMap; 30import android.util.Slog; 31import android.view.Display; 32import android.view.Surface; 33import android.view.SurfaceControl; 34 35import java.io.PrintWriter; 36 37/** 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>(); 49 private Handler mHandler; 50 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); 55 mHandler = handler; 56 } 57 58 public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallbacks callbacks, 59 IMediaProjection projection, int ownerUid, String ownerPackageName, 60 String name, int width, int height, int densityDpi, Surface surface, int flags) { 61 boolean secure = (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0; 62 IBinder appToken = callbacks.asBinder(); 63 IBinder displayToken = SurfaceControl.createDisplay(name, secure); 64 VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken, 65 ownerUid, ownerPackageName, name, width, height, densityDpi, surface, flags, 66 new Callbacks(callbacks, mHandler)); 67 68 mVirtualDisplayDevices.put(appToken, device); 69 70 try { 71 if (projection != null) { 72 projection.addCallback(new MediaProjectionCallback(appToken)); 73 } 74 appToken.linkToDeath(device, 0); 75 } catch (RemoteException ex) { 76 mVirtualDisplayDevices.remove(appToken); 77 device.destroyLocked(); 78 return null; 79 } 80 81 // 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 86 public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) { 87 VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken); 88 if (device != null) { 89 device.setSurfaceLocked(surface); 90 } 91 } 92 93 public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) { 94 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken); 95 if (device != null) { 96 device.destroyLocked(); 97 appToken.unlinkToDeath(device, 0); 98 } 99 100 // Return the display device that was removed without actually sending the 101 // event indicating that it was removed. The caller will handle it. 102 return device; 103 } 104 105 private void handleBinderDiedLocked(IBinder appToken) { 106 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken); 107 if (device != null) { 108 Slog.i(TAG, "Virtual display device released because application token died: " 109 + device.mOwnerPackageName); 110 device.destroyLocked(); 111 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED); 112 } 113 } 114 115 private void handleMediaProjectionStoppedLocked(IBinder appToken) { 116 VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken); 117 if (device != null) { 118 Slog.i(TAG, "Virtual display device released because media projection stopped: " 119 + device.mName); 120 device.stopLocked(); 121 } 122 } 123 124 private final class VirtualDisplayDevice extends DisplayDevice implements DeathRecipient { 125 private final IBinder mAppToken; 126 private final int mOwnerUid; 127 final String mOwnerPackageName; 128 final String mName; 129 private final int mWidth; 130 private final int mHeight; 131 private final int mDensityDpi; 132 private final int mFlags; 133 private final Callbacks mCallbacks; 134 135 private Surface mSurface; 136 private DisplayDeviceInfo mInfo; 137 private int mState; 138 private boolean mStopped; 139 140 public VirtualDisplayDevice(IBinder displayToken, IBinder appToken, 141 int ownerUid, String ownerPackageName, 142 String name, int width, int height, int densityDpi, Surface surface, int flags, 143 Callbacks callbacks) { 144 super(VirtualDisplayAdapter.this, displayToken); 145 mAppToken = appToken; 146 mOwnerUid = ownerUid; 147 mOwnerPackageName = ownerPackageName; 148 mName = name; 149 mWidth = width; 150 mHeight = height; 151 mDensityDpi = densityDpi; 152 mSurface = surface; 153 mFlags = flags; 154 mCallbacks = callbacks; 155 mState = Display.STATE_UNKNOWN; 156 } 157 158 @Override 159 public void binderDied() { 160 synchronized (getSyncRoot()) { 161 if (mSurface != null) { 162 handleBinderDiedLocked(mAppToken); 163 } 164 } 165 } 166 167 public void destroyLocked() { 168 if (mSurface != null) { 169 mSurface.release(); 170 mSurface = null; 171 } 172 SurfaceControl.destroyDisplay(getDisplayTokenLocked()); 173 mCallbacks.dispatchDisplayStopped(); 174 } 175 176 @Override 177 public void requestDisplayStateLocked(int state) { 178 if (state != mState) { 179 mState = state; 180 if (state == Display.STATE_OFF) { 181 mCallbacks.dispatchDisplayPaused(); 182 } else { 183 mCallbacks.dispatchDisplayResumed(); 184 } 185 } 186 } 187 188 @Override 189 public void performTraversalInTransactionLocked() { 190 setSurfaceInTransactionLocked(mSurface); 191 } 192 193 public void setSurfaceLocked(Surface surface) { 194 if (!mStopped && mSurface != surface) { 195 if ((mSurface != null) != (surface != null)) { 196 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 197 } 198 sendTraversalRequestLocked(); 199 mSurface = surface; 200 mInfo = null; 201 } 202 } 203 204 public void stopLocked() { 205 setSurfaceLocked(null); 206 mStopped = true; 207 } 208 209 @Override 210 public void dumpLocked(PrintWriter pw) { 211 super.dumpLocked(pw); 212 pw.println("mFlags=" + mFlags); 213 pw.println("mState=" + Display.stateToString(mState)); 214 pw.println("mStopped=" + mStopped); 215 } 216 217 218 @Override 219 public DisplayDeviceInfo getDisplayDeviceInfoLocked() { 220 if (mInfo == null) { 221 mInfo = new DisplayDeviceInfo(); 222 mInfo.name = mName; 223 mInfo.width = mWidth; 224 mInfo.height = mHeight; 225 mInfo.refreshRate = 60; 226 mInfo.densityDpi = mDensityDpi; 227 mInfo.xDpi = mDensityDpi; 228 mInfo.yDpi = mDensityDpi; 229 mInfo.presentationDeadlineNanos = 1000000000L / (int) mInfo.refreshRate; // 1 frame 230 mInfo.flags = 0; 231 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { 232 mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE; 233 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE) == 0) { 234 mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY 235 | DisplayDeviceInfo.FLAG_NEVER_BLANK; 236 } 237 } else if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) { 238 mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; 239 } 240 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { 241 mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE; 242 } 243 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) { 244 mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION; 245 } 246 mInfo.type = Display.TYPE_VIRTUAL; 247 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE; 248 mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF; 249 mInfo.ownerUid = mOwnerUid; 250 mInfo.ownerPackageName = mOwnerPackageName; 251 } 252 return mInfo; 253 } 254 } 255 256 private static class Callbacks extends Handler { 257 private static final int MSG_ON_DISPLAY_PAUSED = 0; 258 private static final int MSG_ON_DISPLAY_RESUMED = 1; 259 private static final int MSG_ON_DISPLAY_STOPPED = 2; 260 261 private final IVirtualDisplayCallbacks mCallbacks; 262 263 public Callbacks(IVirtualDisplayCallbacks callbacks, Handler handler) { 264 super(handler.getLooper()); 265 mCallbacks = callbacks; 266 } 267 268 @Override 269 public void handleMessage(Message msg) { 270 try { 271 switch (msg.what) { 272 case MSG_ON_DISPLAY_PAUSED: 273 mCallbacks.onDisplayPaused(); 274 break; 275 case MSG_ON_DISPLAY_RESUMED: 276 mCallbacks.onDisplayResumed(); 277 break; 278 case MSG_ON_DISPLAY_STOPPED: 279 mCallbacks.onDisplayStopped(); 280 break; 281 } 282 } catch (RemoteException e) { 283 Slog.w(TAG, "Failed to notify listener of virtual display event.", e); 284 } 285 } 286 287 public void dispatchDisplayPaused() { 288 sendEmptyMessage(MSG_ON_DISPLAY_PAUSED); 289 } 290 291 public void dispatchDisplayResumed() { 292 sendEmptyMessage(MSG_ON_DISPLAY_RESUMED); 293 } 294 295 public void dispatchDisplayStopped() { 296 sendEmptyMessage(MSG_ON_DISPLAY_STOPPED); 297 } 298 } 299 300 private final class MediaProjectionCallback extends IMediaProjectionCallback.Stub { 301 private IBinder mAppToken; 302 public MediaProjectionCallback(IBinder appToken) { 303 mAppToken = appToken; 304 } 305 306 @Override 307 public void onStop() { 308 synchronized (getSyncRoot()) { 309 handleMediaProjectionStoppedLocked(mAppToken); 310 } 311 } 312 } 313} 314