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