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