1 /* 2 * Copyright (C) 2012 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 com.android.internal.util.IndentingPrintWriter; 20 21 import android.Manifest; 22 import android.content.Context; 23 import android.content.pm.PackageManager; 24 import android.hardware.display.DisplayManager; 25 import android.hardware.display.DisplayManagerGlobal; 26 import android.hardware.display.IDisplayManager; 27 import android.hardware.display.IDisplayManagerCallback; 28 import android.hardware.display.WifiDisplayStatus; 29 import android.os.Binder; 30 import android.os.Handler; 31 import android.os.IBinder; 32 import android.os.Looper; 33 import android.os.Message; 34 import android.os.RemoteException; 35 import android.os.SystemClock; 36 import android.os.SystemProperties; 37 import android.text.TextUtils; 38 import android.util.Log; 39 import android.util.Slog; 40 import android.util.SparseArray; 41 import android.view.Display; 42 import android.view.DisplayInfo; 43 import android.view.Surface; 44 45 import com.android.server.UiThread; 46 47 import java.io.FileDescriptor; 48 import java.io.PrintWriter; 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.concurrent.CopyOnWriteArrayList; 52 53 /** 54 * Manages attached displays. 55 * <p> 56 * The {@link DisplayManagerService} manages the global lifecycle of displays, 57 * decides how to configure logical displays based on the physical display devices currently 58 * attached, sends notifications to the system and to applications when the state 59 * changes, and so on. 60 * </p><p> 61 * The display manager service relies on a collection of {@link DisplayAdapter} components, 62 * for discovering and configuring physical display devices attached to the system. 63 * There are separate display adapters for each manner that devices are attached: 64 * one display adapter for built-in local displays, one for simulated non-functional 65 * displays when the system is headless, one for simulated overlay displays used for 66 * development, one for wifi displays, etc. 67 * </p><p> 68 * Display adapters are only weakly coupled to the display manager service. 69 * Display adapters communicate changes in display device state to the display manager 70 * service asynchronously via a {@link DisplayAdapter.Listener} registered 71 * by the display manager service. This separation of concerns is important for 72 * two main reasons. First, it neatly encapsulates the responsibilities of these 73 * two classes: display adapters handle individual display devices whereas 74 * the display manager service handles the global state. Second, it eliminates 75 * the potential for deadlocks resulting from asynchronous display device discovery. 76 * </p> 77 * 78 * <h3>Synchronization</h3> 79 * <p> 80 * Because the display manager may be accessed by multiple threads, the synchronization 81 * story gets a little complicated. In particular, the window manager may call into 82 * the display manager while holding a surface transaction with the expectation that 83 * it can apply changes immediately. Unfortunately, that means we can't just do 84 * everything asynchronously (*grump*). 85 * </p><p> 86 * To make this work, all of the objects that belong to the display manager must 87 * use the same lock. We call this lock the synchronization root and it has a unique 88 * type {@link DisplayManagerService.SyncRoot}. Methods that require this lock are 89 * named with the "Locked" suffix. 90 * </p><p> 91 * Where things get tricky is that the display manager is not allowed to make 92 * any potentially reentrant calls, especially into the window manager. We generally 93 * avoid this by making all potentially reentrant out-calls asynchronous. 94 * </p> 95 */ 96 public final class DisplayManagerService extends IDisplayManager.Stub { 97 private static final String TAG = "DisplayManagerService"; 98 private static final boolean DEBUG = false; 99 100 // When this system property is set to 0, WFD is forcibly disabled on boot. 101 // When this system property is set to 1, WFD is forcibly enabled on boot. 102 // Otherwise WFD is enabled according to the value of config_enableWifiDisplay. 103 private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable"; 104 105 private static final String SYSTEM_HEADLESS = "ro.config.headless"; 106 private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000; 107 108 private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1; 109 private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2; 110 private static final int MSG_DELIVER_DISPLAY_EVENT = 3; 111 private static final int MSG_REQUEST_TRAVERSAL = 4; 112 private static final int MSG_UPDATE_VIEWPORT = 5; 113 114 private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0; 115 private static final int DISPLAY_BLANK_STATE_BLANKED = 1; 116 private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2; 117 118 private final Context mContext; 119 private final boolean mHeadless; 120 private final DisplayManagerHandler mHandler; 121 private final Handler mUiHandler; 122 private final DisplayAdapterListener mDisplayAdapterListener; 123 private WindowManagerFuncs mWindowManagerFuncs; 124 private InputManagerFuncs mInputManagerFuncs; 125 126 // The synchronization root for the display manager. 127 // This lock guards most of the display manager's state. 128 // NOTE: This is synchronized on while holding WindowManagerService.mWindowMap so never call 129 // into WindowManagerService methods that require mWindowMap while holding this unless you are 130 // very very sure that no deadlock can occur. 131 private final SyncRoot mSyncRoot = new SyncRoot(); 132 133 // True if in safe mode. 134 // This option may disable certain display adapters. 135 public boolean mSafeMode; 136 137 // True if we are in a special boot mode where only core applications and 138 // services should be started. This option may disable certain display adapters. 139 public boolean mOnlyCore; 140 141 // True if the display manager service should pretend there is only one display 142 // and only tell applications about the existence of the default logical display. 143 // The display manager can still mirror content to secondary displays but applications 144 // cannot present unique content on those displays. 145 // Used for demonstration purposes only. 146 private final boolean mSingleDisplayDemoMode; 147 148 // All callback records indexed by calling process id. 149 public final SparseArray<CallbackRecord> mCallbacks = 150 new SparseArray<CallbackRecord>(); 151 152 // List of all currently registered display adapters. 153 private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>(); 154 155 // List of all currently connected display devices. 156 private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>(); 157 158 // List of all logical displays indexed by logical display id. 159 private final SparseArray<LogicalDisplay> mLogicalDisplays = 160 new SparseArray<LogicalDisplay>(); 161 private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1; 162 163 // List of all display transaction listeners. 164 private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners = 165 new CopyOnWriteArrayList<DisplayTransactionListener>(); 166 167 // Set to true if all displays have been blanked by the power manager. 168 private int mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNKNOWN; 169 170 // Set to true when there are pending display changes that have yet to be applied 171 // to the surface flinger state. 172 private boolean mPendingTraversal; 173 174 // The Wifi display adapter, or null if not registered. 175 private WifiDisplayAdapter mWifiDisplayAdapter; 176 177 // The number of active wifi display scan requests. 178 private int mWifiDisplayScanRequestCount; 179 180 // The virtual display adapter, or null if not registered. 181 private VirtualDisplayAdapter mVirtualDisplayAdapter; 182 183 // Viewports of the default display and the display that should receive touch 184 // input from an external source. Used by the input system. 185 private final DisplayViewport mDefaultViewport = new DisplayViewport(); 186 private final DisplayViewport mExternalTouchViewport = new DisplayViewport(); 187 188 // Persistent data store for all internal settings maintained by the display manager service. 189 private final PersistentDataStore mPersistentDataStore = new PersistentDataStore(); 190 191 // Temporary callback list, used when sending display events to applications. 192 // May be used outside of the lock but only on the handler thread. 193 private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>(); 194 195 // Temporary display info, used for comparing display configurations. 196 private final DisplayInfo mTempDisplayInfo = new DisplayInfo(); 197 198 // Temporary viewports, used when sending new viewport information to the 199 // input system. May be used outside of the lock but only on the handler thread. 200 private final DisplayViewport mTempDefaultViewport = new DisplayViewport(); 201 private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport(); 202 203 public DisplayManagerService(Context context, Handler mainHandler) { 204 mContext = context; 205 mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1"); 206 207 mHandler = new DisplayManagerHandler(mainHandler.getLooper()); 208 mUiHandler = UiThread.getHandler(); 209 mDisplayAdapterListener = new DisplayAdapterListener(); 210 mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); 211 212 mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER); 213 } 214 215 /** 216 * Pauses the boot process to wait for the first display to be initialized. 217 */ 218 public boolean waitForDefaultDisplay() { 219 synchronized (mSyncRoot) { 220 long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT; 221 while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) { 222 long delay = timeout - SystemClock.uptimeMillis(); 223 if (delay <= 0) { 224 return false; 225 } 226 if (DEBUG) { 227 Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay); 228 } 229 try { 230 mSyncRoot.wait(delay); 231 } catch (InterruptedException ex) { 232 } 233 } 234 } 235 return true; 236 } 237 238 /** 239 * Called during initialization to associate the display manager with the 240 * window manager. 241 */ 242 public void setWindowManager(WindowManagerFuncs windowManagerFuncs) { 243 synchronized (mSyncRoot) { 244 mWindowManagerFuncs = windowManagerFuncs; 245 scheduleTraversalLocked(false); 246 } 247 } 248 249 /** 250 * Called during initialization to associate the display manager with the 251 * input manager. 252 */ 253 public void setInputManager(InputManagerFuncs inputManagerFuncs) { 254 synchronized (mSyncRoot) { 255 mInputManagerFuncs = inputManagerFuncs; 256 scheduleTraversalLocked(false); 257 } 258 } 259 260 /** 261 * Called when the system is ready to go. 262 */ 263 public void systemReady(boolean safeMode, boolean onlyCore) { 264 synchronized (mSyncRoot) { 265 mSafeMode = safeMode; 266 mOnlyCore = onlyCore; 267 } 268 269 mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS); 270 } 271 272 /** 273 * Returns true if the device is headless. 274 * 275 * @return True if the device is headless. 276 */ 277 public boolean isHeadless() { 278 return mHeadless; 279 } 280 281 /** 282 * Registers a display transaction listener to provide the client a chance to 283 * update its surfaces within the same transaction as any display layout updates. 284 * 285 * @param listener The listener to register. 286 */ 287 public void registerDisplayTransactionListener(DisplayTransactionListener listener) { 288 if (listener == null) { 289 throw new IllegalArgumentException("listener must not be null"); 290 } 291 292 // List is self-synchronized copy-on-write. 293 mDisplayTransactionListeners.add(listener); 294 } 295 296 /** 297 * Unregisters a display transaction listener to provide the client a chance to 298 * update its surfaces within the same transaction as any display layout updates. 299 * 300 * @param listener The listener to unregister. 301 */ 302 public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) { 303 if (listener == null) { 304 throw new IllegalArgumentException("listener must not be null"); 305 } 306 307 // List is self-synchronized copy-on-write. 308 mDisplayTransactionListeners.remove(listener); 309 } 310 311 /** 312 * Overrides the display information of a particular logical display. 313 * This is used by the window manager to control the size and characteristics 314 * of the default display. It is expected to apply the requested change 315 * to the display information synchronously so that applications will immediately 316 * observe the new state. 317 * 318 * NOTE: This method must be the only entry point by which the window manager 319 * influences the logical configuration of displays. 320 * 321 * @param displayId The logical display id. 322 * @param info The new data to be stored. 323 */ 324 public void setDisplayInfoOverrideFromWindowManager( 325 int displayId, DisplayInfo info) { 326 synchronized (mSyncRoot) { 327 LogicalDisplay display = mLogicalDisplays.get(displayId); 328 if (display != null) { 329 if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) { 330 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); 331 scheduleTraversalLocked(false); 332 } 333 } 334 } 335 } 336 337 /** 338 * Called by the window manager to perform traversals while holding a 339 * surface flinger transaction. 340 */ 341 public void performTraversalInTransactionFromWindowManager() { 342 synchronized (mSyncRoot) { 343 if (!mPendingTraversal) { 344 return; 345 } 346 mPendingTraversal = false; 347 348 performTraversalInTransactionLocked(); 349 } 350 351 // List is self-synchronized copy-on-write. 352 for (DisplayTransactionListener listener : mDisplayTransactionListeners) { 353 listener.onDisplayTransaction(); 354 } 355 } 356 357 /** 358 * Called by the power manager to blank all displays. 359 */ 360 public void blankAllDisplaysFromPowerManager() { 361 synchronized (mSyncRoot) { 362 if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) { 363 mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED; 364 updateAllDisplayBlankingLocked(); 365 scheduleTraversalLocked(false); 366 } 367 } 368 } 369 370 /** 371 * Called by the power manager to unblank all displays. 372 */ 373 public void unblankAllDisplaysFromPowerManager() { 374 synchronized (mSyncRoot) { 375 if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) { 376 mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED; 377 updateAllDisplayBlankingLocked(); 378 scheduleTraversalLocked(false); 379 } 380 } 381 } 382 383 /** 384 * Returns information about the specified logical display. 385 * 386 * @param displayId The logical display id. 387 * @return The logical display info, or null if the display does not exist. The 388 * returned object must be treated as immutable. 389 */ 390 @Override // Binder call 391 public DisplayInfo getDisplayInfo(int displayId) { 392 final int callingUid = Binder.getCallingUid(); 393 final long token = Binder.clearCallingIdentity(); 394 try { 395 synchronized (mSyncRoot) { 396 LogicalDisplay display = mLogicalDisplays.get(displayId); 397 if (display != null) { 398 DisplayInfo info = display.getDisplayInfoLocked(); 399 if (info.hasAccess(callingUid)) { 400 return info; 401 } 402 } 403 return null; 404 } 405 } finally { 406 Binder.restoreCallingIdentity(token); 407 } 408 } 409 410 /** 411 * Returns the list of all display ids. 412 */ 413 @Override // Binder call 414 public int[] getDisplayIds() { 415 final int callingUid = Binder.getCallingUid(); 416 final long token = Binder.clearCallingIdentity(); 417 try { 418 synchronized (mSyncRoot) { 419 final int count = mLogicalDisplays.size(); 420 int[] displayIds = new int[count]; 421 int n = 0; 422 for (int i = 0; i < count; i++) { 423 LogicalDisplay display = mLogicalDisplays.valueAt(i); 424 DisplayInfo info = display.getDisplayInfoLocked(); 425 if (info.hasAccess(callingUid)) { 426 displayIds[n++] = mLogicalDisplays.keyAt(i); 427 } 428 } 429 if (n != count) { 430 displayIds = Arrays.copyOfRange(displayIds, 0, n); 431 } 432 return displayIds; 433 } 434 } finally { 435 Binder.restoreCallingIdentity(token); 436 } 437 } 438 439 @Override // Binder call 440 public void registerCallback(IDisplayManagerCallback callback) { 441 if (callback == null) { 442 throw new IllegalArgumentException("listener must not be null"); 443 } 444 445 synchronized (mSyncRoot) { 446 int callingPid = Binder.getCallingPid(); 447 if (mCallbacks.get(callingPid) != null) { 448 throw new SecurityException("The calling process has already " 449 + "registered an IDisplayManagerCallback."); 450 } 451 452 CallbackRecord record = new CallbackRecord(callingPid, callback); 453 try { 454 IBinder binder = callback.asBinder(); 455 binder.linkToDeath(record, 0); 456 } catch (RemoteException ex) { 457 // give up 458 throw new RuntimeException(ex); 459 } 460 461 mCallbacks.put(callingPid, record); 462 } 463 } 464 465 private void onCallbackDied(CallbackRecord record) { 466 synchronized (mSyncRoot) { 467 mCallbacks.remove(record.mPid); 468 stopWifiDisplayScanLocked(record); 469 } 470 } 471 472 @Override // Binder call 473 public void startWifiDisplayScan() { 474 mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, 475 "Permission required to start wifi display scans"); 476 477 final int callingPid = Binder.getCallingPid(); 478 final long token = Binder.clearCallingIdentity(); 479 try { 480 synchronized (mSyncRoot) { 481 CallbackRecord record = mCallbacks.get(callingPid); 482 if (record == null) { 483 throw new IllegalStateException("The calling process has not " 484 + "registered an IDisplayManagerCallback."); 485 } 486 startWifiDisplayScanLocked(record); 487 } 488 } finally { 489 Binder.restoreCallingIdentity(token); 490 } 491 } 492 493 private void startWifiDisplayScanLocked(CallbackRecord record) { 494 if (!record.mWifiDisplayScanRequested) { 495 record.mWifiDisplayScanRequested = true; 496 if (mWifiDisplayScanRequestCount++ == 0) { 497 if (mWifiDisplayAdapter != null) { 498 mWifiDisplayAdapter.requestStartScanLocked(); 499 } 500 } 501 } 502 } 503 504 @Override // Binder call 505 public void stopWifiDisplayScan() { 506 mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, 507 "Permission required to stop wifi display scans"); 508 509 final int callingPid = Binder.getCallingPid(); 510 final long token = Binder.clearCallingIdentity(); 511 try { 512 synchronized (mSyncRoot) { 513 CallbackRecord record = mCallbacks.get(callingPid); 514 if (record == null) { 515 throw new IllegalStateException("The calling process has not " 516 + "registered an IDisplayManagerCallback."); 517 } 518 stopWifiDisplayScanLocked(record); 519 } 520 } finally { 521 Binder.restoreCallingIdentity(token); 522 } 523 } 524 525 private void stopWifiDisplayScanLocked(CallbackRecord record) { 526 if (record.mWifiDisplayScanRequested) { 527 record.mWifiDisplayScanRequested = false; 528 if (--mWifiDisplayScanRequestCount == 0) { 529 if (mWifiDisplayAdapter != null) { 530 mWifiDisplayAdapter.requestStopScanLocked(); 531 } 532 } else if (mWifiDisplayScanRequestCount < 0) { 533 Log.wtf(TAG, "mWifiDisplayScanRequestCount became negative: " 534 + mWifiDisplayScanRequestCount); 535 mWifiDisplayScanRequestCount = 0; 536 } 537 } 538 } 539 540 @Override // Binder call 541 public void connectWifiDisplay(String address) { 542 if (address == null) { 543 throw new IllegalArgumentException("address must not be null"); 544 } 545 mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, 546 "Permission required to connect to a wifi display"); 547 548 final long token = Binder.clearCallingIdentity(); 549 try { 550 synchronized (mSyncRoot) { 551 if (mWifiDisplayAdapter != null) { 552 mWifiDisplayAdapter.requestConnectLocked(address); 553 } 554 } 555 } finally { 556 Binder.restoreCallingIdentity(token); 557 } 558 } 559 560 @Override 561 public void pauseWifiDisplay() { 562 mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, 563 "Permission required to pause a wifi display session"); 564 565 final long token = Binder.clearCallingIdentity(); 566 try { 567 synchronized (mSyncRoot) { 568 if (mWifiDisplayAdapter != null) { 569 mWifiDisplayAdapter.requestPauseLocked(); 570 } 571 } 572 } finally { 573 Binder.restoreCallingIdentity(token); 574 } 575 } 576 577 @Override 578 public void resumeWifiDisplay() { 579 mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, 580 "Permission required to resume a wifi display session"); 581 582 final long token = Binder.clearCallingIdentity(); 583 try { 584 synchronized (mSyncRoot) { 585 if (mWifiDisplayAdapter != null) { 586 mWifiDisplayAdapter.requestResumeLocked(); 587 } 588 } 589 } finally { 590 Binder.restoreCallingIdentity(token); 591 } 592 } 593 594 @Override // Binder call 595 public void disconnectWifiDisplay() { 596 // This request does not require special permissions. 597 // Any app can request disconnection from the currently active wifi display. 598 // This exception should no longer be needed once wifi display control moves 599 // to the media router service. 600 601 final long token = Binder.clearCallingIdentity(); 602 try { 603 synchronized (mSyncRoot) { 604 if (mWifiDisplayAdapter != null) { 605 mWifiDisplayAdapter.requestDisconnectLocked(); 606 } 607 } 608 } finally { 609 Binder.restoreCallingIdentity(token); 610 } 611 } 612 613 @Override // Binder call 614 public void renameWifiDisplay(String address, String alias) { 615 if (address == null) { 616 throw new IllegalArgumentException("address must not be null"); 617 } 618 mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, 619 "Permission required to rename to a wifi display"); 620 621 final long token = Binder.clearCallingIdentity(); 622 try { 623 synchronized (mSyncRoot) { 624 if (mWifiDisplayAdapter != null) { 625 mWifiDisplayAdapter.requestRenameLocked(address, alias); 626 } 627 } 628 } finally { 629 Binder.restoreCallingIdentity(token); 630 } 631 } 632 633 @Override // Binder call 634 public void forgetWifiDisplay(String address) { 635 if (address == null) { 636 throw new IllegalArgumentException("address must not be null"); 637 } 638 mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY, 639 "Permission required to forget to a wifi display"); 640 641 final long token = Binder.clearCallingIdentity(); 642 try { 643 synchronized (mSyncRoot) { 644 if (mWifiDisplayAdapter != null) { 645 mWifiDisplayAdapter.requestForgetLocked(address); 646 } 647 } 648 } finally { 649 Binder.restoreCallingIdentity(token); 650 } 651 } 652 653 @Override // Binder call 654 public WifiDisplayStatus getWifiDisplayStatus() { 655 // This request does not require special permissions. 656 // Any app can get information about available wifi displays. 657 658 final long token = Binder.clearCallingIdentity(); 659 try { 660 synchronized (mSyncRoot) { 661 if (mWifiDisplayAdapter != null) { 662 return mWifiDisplayAdapter.getWifiDisplayStatusLocked(); 663 } 664 return new WifiDisplayStatus(); 665 } 666 } finally { 667 Binder.restoreCallingIdentity(token); 668 } 669 } 670 671 @Override // Binder call 672 public int createVirtualDisplay(IBinder appToken, String packageName, 673 String name, int width, int height, int densityDpi, Surface surface, int flags) { 674 final int callingUid = Binder.getCallingUid(); 675 if (!validatePackageName(callingUid, packageName)) { 676 throw new SecurityException("packageName must match the calling uid"); 677 } 678 if (appToken == null) { 679 throw new IllegalArgumentException("appToken must not be null"); 680 } 681 if (TextUtils.isEmpty(name)) { 682 throw new IllegalArgumentException("name must be non-null and non-empty"); 683 } 684 if (width <= 0 || height <= 0 || densityDpi <= 0) { 685 throw new IllegalArgumentException("width, height, and densityDpi must be " 686 + "greater than 0"); 687 } 688 if (surface == null) { 689 throw new IllegalArgumentException("surface must not be null"); 690 } 691 if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) { 692 if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT) 693 != PackageManager.PERMISSION_GRANTED 694 && mContext.checkCallingPermission( 695 android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT) 696 != PackageManager.PERMISSION_GRANTED) { 697 throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or " 698 + "CAPTURE_SECURE_VIDEO_OUTPUT permission to create a " 699 + "public virtual display."); 700 } 701 } 702 if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { 703 if (mContext.checkCallingPermission( 704 android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT) 705 != PackageManager.PERMISSION_GRANTED) { 706 throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT " 707 + "to create a secure virtual display."); 708 } 709 } 710 711 final long token = Binder.clearCallingIdentity(); 712 try { 713 synchronized (mSyncRoot) { 714 if (mVirtualDisplayAdapter == null) { 715 Slog.w(TAG, "Rejecting request to create private virtual display " 716 + "because the virtual display adapter is not available."); 717 return -1; 718 } 719 720 DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked( 721 appToken, callingUid, packageName, name, width, height, densityDpi, 722 surface, flags); 723 if (device == null) { 724 return -1; 725 } 726 727 handleDisplayDeviceAddedLocked(device); 728 LogicalDisplay display = findLogicalDisplayForDeviceLocked(device); 729 if (display != null) { 730 return display.getDisplayIdLocked(); 731 } 732 733 // Something weird happened and the logical display was not created. 734 Slog.w(TAG, "Rejecting request to create virtual display " 735 + "because the logical display was not created."); 736 mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken); 737 handleDisplayDeviceRemovedLocked(device); 738 } 739 } finally { 740 Binder.restoreCallingIdentity(token); 741 } 742 return -1; 743 } 744 745 @Override // Binder call 746 public void releaseVirtualDisplay(IBinder appToken) { 747 final long token = Binder.clearCallingIdentity(); 748 try { 749 synchronized (mSyncRoot) { 750 if (mVirtualDisplayAdapter == null) { 751 return; 752 } 753 754 DisplayDevice device = 755 mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken); 756 if (device != null) { 757 handleDisplayDeviceRemovedLocked(device); 758 } 759 } 760 } finally { 761 Binder.restoreCallingIdentity(token); 762 } 763 } 764 765 private boolean validatePackageName(int uid, String packageName) { 766 if (packageName != null) { 767 String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); 768 if (packageNames != null) { 769 for (String n : packageNames) { 770 if (n.equals(packageName)) { 771 return true; 772 } 773 } 774 } 775 } 776 return false; 777 } 778 779 private void registerDefaultDisplayAdapter() { 780 // Register default display adapter. 781 synchronized (mSyncRoot) { 782 if (mHeadless) { 783 registerDisplayAdapterLocked(new HeadlessDisplayAdapter( 784 mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); 785 } else { 786 registerDisplayAdapterLocked(new LocalDisplayAdapter( 787 mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); 788 } 789 } 790 } 791 792 private void registerAdditionalDisplayAdapters() { 793 synchronized (mSyncRoot) { 794 if (shouldRegisterNonEssentialDisplayAdaptersLocked()) { 795 registerOverlayDisplayAdapterLocked(); 796 registerWifiDisplayAdapterLocked(); 797 registerVirtualDisplayAdapterLocked(); 798 } 799 } 800 } 801 802 private void registerOverlayDisplayAdapterLocked() { 803 registerDisplayAdapterLocked(new OverlayDisplayAdapter( 804 mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler)); 805 } 806 807 private void registerWifiDisplayAdapterLocked() { 808 if (mContext.getResources().getBoolean( 809 com.android.internal.R.bool.config_enableWifiDisplay) 810 || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) { 811 mWifiDisplayAdapter = new WifiDisplayAdapter( 812 mSyncRoot, mContext, mHandler, mDisplayAdapterListener, 813 mPersistentDataStore); 814 registerDisplayAdapterLocked(mWifiDisplayAdapter); 815 } 816 } 817 818 private void registerVirtualDisplayAdapterLocked() { 819 mVirtualDisplayAdapter = new VirtualDisplayAdapter( 820 mSyncRoot, mContext, mHandler, mDisplayAdapterListener); 821 registerDisplayAdapterLocked(mVirtualDisplayAdapter); 822 } 823 824 private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() { 825 // In safe mode, we disable non-essential display adapters to give the user 826 // an opportunity to fix broken settings or other problems that might affect 827 // system stability. 828 // In only-core mode, we disable non-essential display adapters to minimize 829 // the number of dependencies that are started while in this mode and to 830 // prevent problems that might occur due to the device being encrypted. 831 return !mSafeMode && !mOnlyCore; 832 } 833 834 private void registerDisplayAdapterLocked(DisplayAdapter adapter) { 835 mDisplayAdapters.add(adapter); 836 adapter.registerLocked(); 837 } 838 839 private void handleDisplayDeviceAdded(DisplayDevice device) { 840 synchronized (mSyncRoot) { 841 handleDisplayDeviceAddedLocked(device); 842 } 843 } 844 845 private void handleDisplayDeviceAddedLocked(DisplayDevice device) { 846 if (mDisplayDevices.contains(device)) { 847 Slog.w(TAG, "Attempted to add already added display device: " 848 + device.getDisplayDeviceInfoLocked()); 849 return; 850 } 851 852 Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked()); 853 854 mDisplayDevices.add(device); 855 addLogicalDisplayLocked(device); 856 updateDisplayBlankingLocked(device); 857 scheduleTraversalLocked(false); 858 } 859 860 private void handleDisplayDeviceChanged(DisplayDevice device) { 861 synchronized (mSyncRoot) { 862 if (!mDisplayDevices.contains(device)) { 863 Slog.w(TAG, "Attempted to change non-existent display device: " 864 + device.getDisplayDeviceInfoLocked()); 865 return; 866 } 867 868 Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked()); 869 870 device.applyPendingDisplayDeviceInfoChangesLocked(); 871 if (updateLogicalDisplaysLocked()) { 872 scheduleTraversalLocked(false); 873 } 874 } 875 } 876 877 private void handleDisplayDeviceRemoved(DisplayDevice device) { 878 synchronized (mSyncRoot) { 879 handleDisplayDeviceRemovedLocked(device); 880 } 881 } 882 private void handleDisplayDeviceRemovedLocked(DisplayDevice device) { 883 if (!mDisplayDevices.remove(device)) { 884 Slog.w(TAG, "Attempted to remove non-existent display device: " 885 + device.getDisplayDeviceInfoLocked()); 886 return; 887 } 888 889 Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked()); 890 891 updateLogicalDisplaysLocked(); 892 scheduleTraversalLocked(false); 893 } 894 895 private void updateAllDisplayBlankingLocked() { 896 final int count = mDisplayDevices.size(); 897 for (int i = 0; i < count; i++) { 898 DisplayDevice device = mDisplayDevices.get(i); 899 updateDisplayBlankingLocked(device); 900 } 901 } 902 903 private void updateDisplayBlankingLocked(DisplayDevice device) { 904 // Blank or unblank the display immediately to match the state requested 905 // by the power manager (if known). 906 DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 907 if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { 908 switch (mAllDisplayBlankStateFromPowerManager) { 909 case DISPLAY_BLANK_STATE_BLANKED: 910 device.blankLocked(); 911 break; 912 case DISPLAY_BLANK_STATE_UNBLANKED: 913 device.unblankLocked(); 914 break; 915 } 916 } 917 } 918 919 // Adds a new logical display based on the given display device. 920 // Sends notifications if needed. 921 private void addLogicalDisplayLocked(DisplayDevice device) { 922 DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); 923 boolean isDefault = (deviceInfo.flags 924 & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0; 925 if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) { 926 Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo); 927 isDefault = false; 928 } 929 930 if (!isDefault && mSingleDisplayDemoMode) { 931 Slog.i(TAG, "Not creating a logical display for a secondary display " 932 + " because single display demo mode is enabled: " + deviceInfo); 933 return; 934 } 935 936 final int displayId = assignDisplayIdLocked(isDefault); 937 final int layerStack = assignLayerStackLocked(displayId); 938 939 LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device); 940 display.updateLocked(mDisplayDevices); 941 if (!display.isValidLocked()) { 942 // This should never happen currently. 943 Slog.w(TAG, "Ignoring display device because the logical display " 944 + "created from it was not considered valid: " + deviceInfo); 945 return; 946 } 947 948 mLogicalDisplays.put(displayId, display); 949 950 // Wake up waitForDefaultDisplay. 951 if (isDefault) { 952 mSyncRoot.notifyAll(); 953 } 954 955 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED); 956 } 957 958 private int assignDisplayIdLocked(boolean isDefault) { 959 return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++; 960 } 961 962 private int assignLayerStackLocked(int displayId) { 963 // Currently layer stacks and display ids are the same. 964 // This need not be the case. 965 return displayId; 966 } 967 968 // Updates all existing logical displays given the current set of display devices. 969 // Removes invalid logical displays. 970 // Sends notifications if needed. 971 private boolean updateLogicalDisplaysLocked() { 972 boolean changed = false; 973 for (int i = mLogicalDisplays.size(); i-- > 0; ) { 974 final int displayId = mLogicalDisplays.keyAt(i); 975 LogicalDisplay display = mLogicalDisplays.valueAt(i); 976 977 mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked()); 978 display.updateLocked(mDisplayDevices); 979 if (!display.isValidLocked()) { 980 mLogicalDisplays.removeAt(i); 981 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); 982 changed = true; 983 } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) { 984 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); 985 changed = true; 986 } 987 } 988 return changed; 989 } 990 991 private void performTraversalInTransactionLocked() { 992 // Clear all viewports before configuring displays so that we can keep 993 // track of which ones we have configured. 994 clearViewportsLocked(); 995 996 // Configure each display device. 997 final int count = mDisplayDevices.size(); 998 for (int i = 0; i < count; i++) { 999 DisplayDevice device = mDisplayDevices.get(i); 1000 configureDisplayInTransactionLocked(device); 1001 device.performTraversalInTransactionLocked(); 1002 } 1003 1004 // Tell the input system about these new viewports. 1005 if (mInputManagerFuncs != null) { 1006 mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT); 1007 } 1008 } 1009 1010 /** 1011 * Tells the display manager whether there is interesting unique content on the 1012 * specified logical display. This is used to control automatic mirroring. 1013 * <p> 1014 * If the display has unique content, then the display manager arranges for it 1015 * to be presented on a physical display if appropriate. Otherwise, the display manager 1016 * may choose to make the physical display mirror some other logical display. 1017 * </p> 1018 * 1019 * @param displayId The logical display id to update. 1020 * @param hasContent True if the logical display has content. 1021 * @param inTraversal True if called from WindowManagerService during a window traversal prior 1022 * to call to performTraversalInTransactionFromWindowManager. 1023 */ 1024 public void setDisplayHasContent(int displayId, boolean hasContent, boolean inTraversal) { 1025 synchronized (mSyncRoot) { 1026 LogicalDisplay display = mLogicalDisplays.get(displayId); 1027 if (display != null && display.hasContentLocked() != hasContent) { 1028 if (DEBUG) { 1029 Slog.d(TAG, "Display " + displayId + " hasContent flag changed: " 1030 + "hasContent=" + hasContent + ", inTraversal=" + inTraversal); 1031 } 1032 1033 display.setHasContentLocked(hasContent); 1034 scheduleTraversalLocked(inTraversal); 1035 } 1036 } 1037 } 1038 1039 private void clearViewportsLocked() { 1040 mDefaultViewport.valid = false; 1041 mExternalTouchViewport.valid = false; 1042 } 1043 1044 private void configureDisplayInTransactionLocked(DisplayDevice device) { 1045 DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 1046 boolean isPrivate = (info.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0; 1047 1048 // Find the logical display that the display device is showing. 1049 // Private displays never mirror other displays. 1050 LogicalDisplay display = findLogicalDisplayForDeviceLocked(device); 1051 if (!isPrivate) { 1052 if (display != null && !display.hasContentLocked()) { 1053 // If the display does not have any content of its own, then 1054 // automatically mirror the default logical display contents. 1055 display = null; 1056 } 1057 if (display == null) { 1058 display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY); 1059 } 1060 } 1061 1062 // Apply the logical display configuration to the display device. 1063 if (display == null) { 1064 // TODO: no logical display for the device, blank it 1065 Slog.w(TAG, "Missing logical display to use for physical display device: " 1066 + device.getDisplayDeviceInfoLocked()); 1067 return; 1068 } 1069 boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED) 1070 && (info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0; 1071 display.configureDisplayInTransactionLocked(device, isBlanked); 1072 1073 // Update the viewports if needed. 1074 if (!mDefaultViewport.valid 1075 && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) { 1076 setViewportLocked(mDefaultViewport, display, device); 1077 } 1078 if (!mExternalTouchViewport.valid 1079 && info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) { 1080 setViewportLocked(mExternalTouchViewport, display, device); 1081 } 1082 } 1083 1084 private static void setViewportLocked(DisplayViewport viewport, 1085 LogicalDisplay display, DisplayDevice device) { 1086 viewport.valid = true; 1087 viewport.displayId = display.getDisplayIdLocked(); 1088 device.populateViewportLocked(viewport); 1089 } 1090 1091 private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) { 1092 final int count = mLogicalDisplays.size(); 1093 for (int i = 0; i < count; i++) { 1094 LogicalDisplay display = mLogicalDisplays.valueAt(i); 1095 if (display.getPrimaryDisplayDeviceLocked() == device) { 1096 return display; 1097 } 1098 } 1099 return null; 1100 } 1101 1102 private void sendDisplayEventLocked(int displayId, int event) { 1103 Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event); 1104 mHandler.sendMessage(msg); 1105 } 1106 1107 // Requests that performTraversalsInTransactionFromWindowManager be called at a 1108 // later time to apply changes to surfaces and displays. 1109 private void scheduleTraversalLocked(boolean inTraversal) { 1110 if (!mPendingTraversal && mWindowManagerFuncs != null) { 1111 mPendingTraversal = true; 1112 if (!inTraversal) { 1113 mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL); 1114 } 1115 } 1116 } 1117 1118 // Runs on Handler thread. 1119 // Delivers display event notifications to callbacks. 1120 private void deliverDisplayEvent(int displayId, int event) { 1121 if (DEBUG) { 1122 Slog.d(TAG, "Delivering display event: displayId=" 1123 + displayId + ", event=" + event); 1124 } 1125 1126 // Grab the lock and copy the callbacks. 1127 final int count; 1128 synchronized (mSyncRoot) { 1129 count = mCallbacks.size(); 1130 mTempCallbacks.clear(); 1131 for (int i = 0; i < count; i++) { 1132 mTempCallbacks.add(mCallbacks.valueAt(i)); 1133 } 1134 } 1135 1136 // After releasing the lock, send the notifications out. 1137 for (int i = 0; i < count; i++) { 1138 mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event); 1139 } 1140 mTempCallbacks.clear(); 1141 } 1142 1143 @Override // Binder call 1144 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 1145 if (mContext == null 1146 || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 1147 != PackageManager.PERMISSION_GRANTED) { 1148 pw.println("Permission Denial: can't dump DisplayManager from from pid=" 1149 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 1150 return; 1151 } 1152 1153 pw.println("DISPLAY MANAGER (dumpsys display)"); 1154 1155 synchronized (mSyncRoot) { 1156 pw.println(" mHeadless=" + mHeadless); 1157 pw.println(" mOnlyCode=" + mOnlyCore); 1158 pw.println(" mSafeMode=" + mSafeMode); 1159 pw.println(" mPendingTraversal=" + mPendingTraversal); 1160 pw.println(" mAllDisplayBlankStateFromPowerManager=" 1161 + mAllDisplayBlankStateFromPowerManager); 1162 pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId); 1163 pw.println(" mDefaultViewport=" + mDefaultViewport); 1164 pw.println(" mExternalTouchViewport=" + mExternalTouchViewport); 1165 pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode); 1166 pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount); 1167 1168 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 1169 ipw.increaseIndent(); 1170 1171 pw.println(); 1172 pw.println("Display Adapters: size=" + mDisplayAdapters.size()); 1173 for (DisplayAdapter adapter : mDisplayAdapters) { 1174 pw.println(" " + adapter.getName()); 1175 adapter.dumpLocked(ipw); 1176 } 1177 1178 pw.println(); 1179 pw.println("Display Devices: size=" + mDisplayDevices.size()); 1180 for (DisplayDevice device : mDisplayDevices) { 1181 pw.println(" " + device.getDisplayDeviceInfoLocked()); 1182 device.dumpLocked(ipw); 1183 } 1184 1185 final int logicalDisplayCount = mLogicalDisplays.size(); 1186 pw.println(); 1187 pw.println("Logical Displays: size=" + logicalDisplayCount); 1188 for (int i = 0; i < logicalDisplayCount; i++) { 1189 int displayId = mLogicalDisplays.keyAt(i); 1190 LogicalDisplay display = mLogicalDisplays.valueAt(i); 1191 pw.println(" Display " + displayId + ":"); 1192 display.dumpLocked(ipw); 1193 } 1194 1195 final int callbackCount = mCallbacks.size(); 1196 pw.println(); 1197 pw.println("Callbacks: size=" + callbackCount); 1198 for (int i = 0; i < callbackCount; i++) { 1199 CallbackRecord callback = mCallbacks.valueAt(i); 1200 pw.println(" " + i + ": mPid=" + callback.mPid 1201 + ", mWifiDisplayScanRequested=" + callback.mWifiDisplayScanRequested); 1202 } 1203 } 1204 } 1205 1206 /** 1207 * This is the object that everything in the display manager locks on. 1208 * We make it an inner class within the {@link DisplayManagerService} to so that it is 1209 * clear that the object belongs to the display manager service and that it is 1210 * a unique object with a special purpose. 1211 */ 1212 public static final class SyncRoot { 1213 } 1214 1215 /** 1216 * Private interface to the window manager. 1217 */ 1218 public interface WindowManagerFuncs { 1219 /** 1220 * Request that the window manager call 1221 * {@link #performTraversalInTransactionFromWindowManager} within a surface 1222 * transaction at a later time. 1223 */ 1224 void requestTraversal(); 1225 } 1226 1227 /** 1228 * Private interface to the input manager. 1229 */ 1230 public interface InputManagerFuncs { 1231 /** 1232 * Sets information about the displays as needed by the input system. 1233 * The input system should copy this information if required. 1234 */ 1235 void setDisplayViewports(DisplayViewport defaultViewport, 1236 DisplayViewport externalTouchViewport); 1237 } 1238 1239 private final class DisplayManagerHandler extends Handler { 1240 public DisplayManagerHandler(Looper looper) { 1241 super(looper, null, true /*async*/); 1242 } 1243 1244 @Override 1245 public void handleMessage(Message msg) { 1246 switch (msg.what) { 1247 case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER: 1248 registerDefaultDisplayAdapter(); 1249 break; 1250 1251 case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS: 1252 registerAdditionalDisplayAdapters(); 1253 break; 1254 1255 case MSG_DELIVER_DISPLAY_EVENT: 1256 deliverDisplayEvent(msg.arg1, msg.arg2); 1257 break; 1258 1259 case MSG_REQUEST_TRAVERSAL: 1260 mWindowManagerFuncs.requestTraversal(); 1261 break; 1262 1263 case MSG_UPDATE_VIEWPORT: { 1264 synchronized (mSyncRoot) { 1265 mTempDefaultViewport.copyFrom(mDefaultViewport); 1266 mTempExternalTouchViewport.copyFrom(mExternalTouchViewport); 1267 } 1268 mInputManagerFuncs.setDisplayViewports( 1269 mTempDefaultViewport, mTempExternalTouchViewport); 1270 break; 1271 } 1272 } 1273 } 1274 } 1275 1276 private final class DisplayAdapterListener implements DisplayAdapter.Listener { 1277 @Override 1278 public void onDisplayDeviceEvent(DisplayDevice device, int event) { 1279 switch (event) { 1280 case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED: 1281 handleDisplayDeviceAdded(device); 1282 break; 1283 1284 case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED: 1285 handleDisplayDeviceChanged(device); 1286 break; 1287 1288 case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED: 1289 handleDisplayDeviceRemoved(device); 1290 break; 1291 } 1292 } 1293 1294 @Override 1295 public void onTraversalRequested() { 1296 synchronized (mSyncRoot) { 1297 scheduleTraversalLocked(false); 1298 } 1299 } 1300 } 1301 1302 private final class CallbackRecord implements DeathRecipient { 1303 public final int mPid; 1304 private final IDisplayManagerCallback mCallback; 1305 1306 public boolean mWifiDisplayScanRequested; 1307 1308 public CallbackRecord(int pid, IDisplayManagerCallback callback) { 1309 mPid = pid; 1310 mCallback = callback; 1311 } 1312 1313 @Override 1314 public void binderDied() { 1315 if (DEBUG) { 1316 Slog.d(TAG, "Display listener for pid " + mPid + " died."); 1317 } 1318 onCallbackDied(this); 1319 } 1320 1321 public void notifyDisplayEventAsync(int displayId, int event) { 1322 try { 1323 mCallback.onDisplayEvent(displayId, event); 1324 } catch (RemoteException ex) { 1325 Slog.w(TAG, "Failed to notify process " 1326 + mPid + " that displays changed, assuming it died.", ex); 1327 binderDied(); 1328 } 1329 } 1330 } 1331 } 1332