DisplayManagerService.java revision cbad976b2a36a0895ca94510d5208a86f66cf596
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.DisplayManagerGlobal; 25import android.hardware.display.IDisplayManager; 26import android.hardware.display.IDisplayManagerCallback; 27import android.os.Binder; 28import android.os.Handler; 29import android.os.IBinder; 30import android.os.Looper; 31import android.os.Message; 32import android.os.RemoteException; 33import android.os.SystemClock; 34import android.os.SystemProperties; 35import android.util.Slog; 36import android.util.SparseArray; 37import android.view.Display; 38import android.view.DisplayInfo; 39 40import java.io.FileDescriptor; 41import java.io.PrintWriter; 42import java.util.ArrayList; 43 44/** 45 * Manages attached displays. 46 * <p> 47 * The {@link DisplayManagerService} manages the global lifecycle of displays, 48 * decides how to configure logical displays based on the physical display devices currently 49 * attached, sends notifications to the system and to applications when the state 50 * changes, and so on. 51 * </p><p> 52 * The display manager service relies on a collection of {@link DisplayAdapter} components, 53 * for discovering and configuring physical display devices attached to the system. 54 * There are separate display adapters for each manner that devices are attached: 55 * one display adapter for built-in local displays, one for simulated non-functional 56 * displays when the system is headless, one for simulated overlay displays used for 57 * development, one for wifi displays, etc. 58 * </p><p> 59 * Display adapters are only weakly coupled to the display manager service. 60 * Display adapters communicate changes in display device state to the display manager 61 * service asynchronously via a {@link DisplayAdapter.DisplayAdapterListener} registered 62 * by the display manager service. This separation of concerns is important for 63 * two main reasons. First, it neatly encapsulates the responsibilities of these 64 * two classes: display adapters handle individual display devices whereas 65 * the display manager service handles the global state. Second, it eliminates 66 * the potential for deadlocks resulting from asynchronous display device discovery. 67 * </p> 68 * 69 * <h3>Synchronization</h3> 70 * <p> 71 * Because the display manager may be accessed by multiple threads, the synchronization 72 * story gets a little complicated. In particular, the window manager may call into 73 * the display manager while holding a surface transaction with the expectation that 74 * it can apply changes immediately. Unfortunately, that means we can't just do 75 * everything asynchronously (*grump*). 76 * </p><p> 77 * To make this work, all of the objects that belong to the display manager must 78 * use the same lock. We call this lock the synchronization root and it has a unique 79 * type {@link DisplayManagerService.SyncRoot}. Methods that require this lock are 80 * named with the "Locked" suffix. 81 * </p><p> 82 * Where things get tricky is that the display manager is not allowed to make 83 * any potentially reentrant calls, especially into the window manager. We generally 84 * avoid this by making all potentially reentrant out-calls asynchronous. 85 * </p> 86 */ 87public final class DisplayManagerService extends IDisplayManager.Stub { 88 private static final String TAG = "DisplayManagerService"; 89 private static final boolean DEBUG = false; 90 91 private static final String SYSTEM_HEADLESS = "ro.config.headless"; 92 private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000; 93 94 private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1; 95 private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2; 96 private static final int MSG_DELIVER_DISPLAY_EVENT = 3; 97 private static final int MSG_REQUEST_TRAVERSAL = 4; 98 99 private final Context mContext; 100 private final boolean mHeadless; 101 private final DisplayManagerHandler mHandler; 102 private final Handler mUiHandler; 103 private final DisplayAdapterListener mDisplayAdapterListener; 104 private WindowManagerFuncs mWindowManagerFuncs; 105 106 // The synchronization root for the display manager. 107 // This lock guards most of the display manager's state. 108 private final SyncRoot mSyncRoot = new SyncRoot(); 109 110 // True if in safe mode. 111 // This option may disable certain display adapters. 112 public boolean mSafeMode; 113 114 // True if we are in a special boot mode where only core applications and 115 // services should be started. This option may disable certain display adapters. 116 public boolean mOnlyCore; 117 118 // All callback records indexed by calling process id. 119 public final SparseArray<CallbackRecord> mCallbacks = 120 new SparseArray<CallbackRecord>(); 121 122 // List of all currently registered display adapters. 123 private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>(); 124 125 // List of all currently connected display devices. 126 private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>(); 127 128 // List of all removed display devices. 129 private final ArrayList<DisplayDevice> mRemovedDisplayDevices = new ArrayList<DisplayDevice>(); 130 131 // List of all logical displays indexed by logical display id. 132 private final SparseArray<LogicalDisplay> mLogicalDisplays = 133 new SparseArray<LogicalDisplay>(); 134 private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1; 135 136 // Set to true when there are pending display changes that have yet to be applied 137 // to the surface flinger state. 138 private boolean mPendingTraversal; 139 140 // Temporary callback list, used when sending display events to applications. 141 // May be used outside of the lock but only on the handler thread. 142 private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>(); 143 144 // Temporary display info, used for comparing display configurations. 145 private final DisplayInfo mTempDisplayInfo = new DisplayInfo(); 146 147 public DisplayManagerService(Context context, Handler mainHandler, Handler uiHandler) { 148 mContext = context; 149 mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1"); 150 151 mHandler = new DisplayManagerHandler(mainHandler.getLooper()); 152 mUiHandler = uiHandler; 153 mDisplayAdapterListener = new DisplayAdapterListener(); 154 155 mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER); 156 } 157 158 /** 159 * Pauses the boot process to wait for the first display to be initialized. 160 */ 161 public boolean waitForDefaultDisplay() { 162 synchronized (mSyncRoot) { 163 long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT; 164 while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) { 165 long delay = timeout - SystemClock.uptimeMillis(); 166 if (delay <= 0) { 167 return false; 168 } 169 if (DEBUG) { 170 Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay); 171 } 172 try { 173 mSyncRoot.wait(delay); 174 } catch (InterruptedException ex) { 175 } 176 } 177 } 178 return true; 179 } 180 181 /** 182 * Called during initialization to associated the display manager with the 183 * window manager. 184 */ 185 public void setWindowManager(WindowManagerFuncs windowManagerFuncs) { 186 synchronized (mSyncRoot) { 187 mWindowManagerFuncs = windowManagerFuncs; 188 scheduleTraversalLocked(); 189 } 190 } 191 192 /** 193 * Called when the system is ready to go. 194 */ 195 public void systemReady(boolean safeMode, boolean onlyCore) { 196 synchronized (mSyncRoot) { 197 mSafeMode = safeMode; 198 mOnlyCore = onlyCore; 199 } 200 201 mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS); 202 } 203 204 /** 205 * Returns true if the device is headless. 206 * 207 * @return True if the device is headless. 208 */ 209 public boolean isHeadless() { 210 return mHeadless; 211 } 212 213 /** 214 * Overrides the display information of a particular logical display. 215 * This is used by the window manager to control the size and characteristics 216 * of the default display. It is expected to apply the requested change 217 * to the display information synchronously so that applications will immediately 218 * observe the new state. 219 * 220 * @param displayId The logical display id. 221 * @param info The new data to be stored. 222 */ 223 public void setDisplayInfoOverrideFromWindowManager( 224 int displayId, DisplayInfo info) { 225 synchronized (mSyncRoot) { 226 LogicalDisplay display = mLogicalDisplays.get(displayId); 227 if (display != null) { 228 mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked()); 229 display.setDisplayInfoOverrideFromWindowManagerLocked(info); 230 if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) { 231 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); 232 scheduleTraversalLocked(); 233 } 234 } 235 } 236 } 237 238 /** 239 * Called by the window manager to perform traversals while holding a 240 * surface flinger transaction. 241 */ 242 public void performTraversalInTransactionFromWindowManager() { 243 synchronized (mSyncRoot) { 244 if (!mPendingTraversal) { 245 return; 246 } 247 mPendingTraversal = false; 248 249 performTraversalInTransactionLocked(); 250 } 251 } 252 253 /** 254 * Returns information about the specified logical display. 255 * 256 * @param displayId The logical display id. 257 * @param The logical display info, or null if the display does not exist. 258 * This object must be treated as immutable. 259 */ 260 @Override // Binder call 261 public DisplayInfo getDisplayInfo(int displayId) { 262 synchronized (mSyncRoot) { 263 LogicalDisplay display = mLogicalDisplays.get(displayId); 264 if (display != null) { 265 return display.getDisplayInfoLocked(); 266 } 267 return null; 268 } 269 } 270 271 /** 272 * Returns the list of all display ids. 273 */ 274 @Override // Binder call 275 public int[] getDisplayIds() { 276 synchronized (mSyncRoot) { 277 final int count = mLogicalDisplays.size(); 278 int[] displayIds = new int[count]; 279 for (int i = 0; i < count; i++) { 280 displayIds[i] = mLogicalDisplays.keyAt(i); 281 } 282 return displayIds; 283 } 284 } 285 286 @Override // Binder call 287 public void registerCallback(IDisplayManagerCallback callback) { 288 if (callback == null) { 289 throw new IllegalArgumentException("listener must not be null"); 290 } 291 292 synchronized (mSyncRoot) { 293 int callingPid = Binder.getCallingPid(); 294 if (mCallbacks.get(callingPid) != null) { 295 throw new SecurityException("The calling process has already " 296 + "registered an IDisplayManagerCallback."); 297 } 298 299 CallbackRecord record = new CallbackRecord(callingPid, callback); 300 try { 301 IBinder binder = callback.asBinder(); 302 binder.linkToDeath(record, 0); 303 } catch (RemoteException ex) { 304 // give up 305 throw new RuntimeException(ex); 306 } 307 308 mCallbacks.put(callingPid, record); 309 } 310 } 311 312 private void onCallbackDied(int pid) { 313 synchronized (mSyncRoot) { 314 mCallbacks.remove(pid); 315 } 316 } 317 318 private void registerDefaultDisplayAdapter() { 319 // Register default display adapter. 320 synchronized (mSyncRoot) { 321 if (mHeadless) { 322 registerDisplayAdapterLocked(new HeadlessDisplayAdapter( 323 mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); 324 } else { 325 registerDisplayAdapterLocked(new LocalDisplayAdapter( 326 mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); 327 } 328 } 329 } 330 331 private void registerAdditionalDisplayAdapters() { 332 synchronized (mSyncRoot) { 333 if (shouldRegisterNonEssentialDisplayAdaptersLocked()) { 334 registerDisplayAdapterLocked(new OverlayDisplayAdapter( 335 mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler)); 336 registerDisplayAdapterLocked(new WifiDisplayAdapter( 337 mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); 338 } 339 } 340 } 341 342 private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() { 343 // In safe mode, we disable non-essential display adapters to give the user 344 // an opportunity to fix broken settings or other problems that might affect 345 // system stability. 346 // In only-core mode, we disable non-essential display adapters to minimize 347 // the number of dependencies that are started while in this mode and to 348 // prevent problems that might occur due to the device being encrypted. 349 return !mSafeMode && !mOnlyCore; 350 } 351 352 private void registerDisplayAdapterLocked(DisplayAdapter adapter) { 353 mDisplayAdapters.add(adapter); 354 adapter.registerLocked(); 355 } 356 357 private void handleDisplayDeviceAdded(DisplayDevice device) { 358 synchronized (mSyncRoot) { 359 if (mDisplayDevices.contains(device)) { 360 Slog.w(TAG, "Attempted to add already added display device: " 361 + device.getDisplayDeviceInfoLocked()); 362 return; 363 } 364 365 mDisplayDevices.add(device); 366 addLogicalDisplayLocked(device); 367 scheduleTraversalLocked(); 368 } 369 } 370 371 private void handleDisplayDeviceChanged(DisplayDevice device) { 372 synchronized (mSyncRoot) { 373 if (!mDisplayDevices.contains(device)) { 374 Slog.w(TAG, "Attempted to change non-existent display device: " 375 + device.getDisplayDeviceInfoLocked()); 376 return; 377 } 378 379 device.applyPendingDisplayDeviceInfoChangesLocked(); 380 if (updateLogicalDisplaysLocked()) { 381 scheduleTraversalLocked(); 382 } 383 } 384 } 385 386 private void handleDisplayDeviceRemoved(DisplayDevice device) { 387 synchronized (mSyncRoot) { 388 if (!mDisplayDevices.remove(device)) { 389 Slog.w(TAG, "Attempted to remove non-existent display device: " 390 + device.getDisplayDeviceInfoLocked()); 391 return; 392 } 393 394 mRemovedDisplayDevices.add(device); 395 updateLogicalDisplaysLocked(); 396 scheduleTraversalLocked(); 397 } 398 } 399 400 // Adds a new logical display based on the given display device. 401 // Sends notifications if needed. 402 private void addLogicalDisplayLocked(DisplayDevice device) { 403 DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); 404 boolean isDefault = (deviceInfo.flags 405 & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0; 406 if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) { 407 Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo); 408 isDefault = false; 409 } 410 411 final int displayId = assignDisplayIdLocked(isDefault); 412 final int layerStack = assignLayerStackLocked(displayId); 413 414 LogicalDisplay display = new LogicalDisplay(layerStack, device); 415 display.updateLocked(mDisplayDevices); 416 if (!display.isValidLocked()) { 417 // This should never happen currently. 418 Slog.w(TAG, "Ignoring display device because the logical display " 419 + "created from it was not considered valid: " + deviceInfo); 420 return; 421 } 422 423 mLogicalDisplays.put(displayId, display); 424 425 // Wake up waitForDefaultDisplay. 426 if (isDefault) { 427 mSyncRoot.notifyAll(); 428 } 429 430 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED); 431 } 432 433 private int assignDisplayIdLocked(boolean isDefault) { 434 return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++; 435 } 436 437 private int assignLayerStackLocked(int displayId) { 438 // Currently layer stacks and display ids are the same. 439 // This need not be the case. 440 return displayId; 441 } 442 443 // Updates all existing logical displays given the current set of display devices. 444 // Removes invalid logical displays. 445 // Sends notifications if needed. 446 private boolean updateLogicalDisplaysLocked() { 447 boolean changed = false; 448 for (int i = mLogicalDisplays.size(); i-- > 0; ) { 449 final int displayId = mLogicalDisplays.keyAt(i); 450 LogicalDisplay display = mLogicalDisplays.valueAt(i); 451 452 mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked()); 453 display.updateLocked(mDisplayDevices); 454 if (!display.isValidLocked()) { 455 mLogicalDisplays.removeAt(i); 456 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); 457 changed = true; 458 } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) { 459 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); 460 changed = true; 461 } 462 } 463 return changed; 464 } 465 466 private void performTraversalInTransactionLocked() { 467 // Perform one last traversal for each removed display device. 468 final int removedCount = mRemovedDisplayDevices.size(); 469 for (int i = 0; i < removedCount; i++) { 470 DisplayDevice device = mRemovedDisplayDevices.get(i); 471 device.performTraversalInTransactionLocked(); 472 } 473 mRemovedDisplayDevices.clear(); 474 475 // Configure each display device. 476 final int count = mDisplayDevices.size(); 477 for (int i = 0; i < count; i++) { 478 DisplayDevice device = mDisplayDevices.get(i); 479 configureDisplayInTransactionLocked(device); 480 device.performTraversalInTransactionLocked(); 481 } 482 } 483 484 private void configureDisplayInTransactionLocked(DisplayDevice device) { 485 // TODO: add a proper per-display mirroring control 486 boolean isMirroring = SystemProperties.getBoolean("debug.display.mirror", true); 487 488 // Find the logical display that the display device is showing. 489 LogicalDisplay display = null; 490 if (!isMirroring) { 491 display = findLogicalDisplayForDeviceLocked(device); 492 } 493 if (display == null) { 494 display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY); 495 } 496 497 // Apply the logical display configuration to the display device. 498 if (display == null) { 499 // TODO: no logical display for the device, blank it 500 Slog.d(TAG, "Missing logical display to use for physical display device: " 501 + device.getDisplayDeviceInfoLocked()); 502 } else { 503 display.configureDisplayInTransactionLocked(device); 504 } 505 } 506 507 private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) { 508 final int count = mLogicalDisplays.size(); 509 for (int i = 0; i < count; i++) { 510 LogicalDisplay display = mLogicalDisplays.valueAt(i); 511 if (display.getPrimaryDisplayDeviceLocked() == device) { 512 return display; 513 } 514 } 515 return null; 516 } 517 518 private void sendDisplayEventLocked(int displayId, int event) { 519 Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event); 520 mHandler.sendMessage(msg); 521 } 522 523 // Requests that performTraversalsInTransactionFromWindowManager be called at a 524 // later time to apply changes to surfaces and displays. 525 private void scheduleTraversalLocked() { 526 if (!mPendingTraversal && mWindowManagerFuncs != null) { 527 mPendingTraversal = true; 528 mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL); 529 } 530 } 531 532 // Runs on Handler thread. 533 // Delivers display event notifications to callbacks. 534 private void deliverDisplayEvent(int displayId, int event) { 535 if (DEBUG) { 536 Slog.d(TAG, "Delivering display event: displayId=" 537 + displayId + ", event=" + event); 538 } 539 540 // Grab the lock and copy the callbacks. 541 final int count; 542 synchronized (mSyncRoot) { 543 count = mCallbacks.size(); 544 mTempCallbacks.clear(); 545 for (int i = 0; i < count; i++) { 546 mTempCallbacks.add(mCallbacks.valueAt(i)); 547 } 548 } 549 550 // After releasing the lock, send the notifications out. 551 for (int i = 0; i < count; i++) { 552 mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event); 553 } 554 mTempCallbacks.clear(); 555 } 556 557 @Override // Binder call 558 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 559 if (mContext == null 560 || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 561 != PackageManager.PERMISSION_GRANTED) { 562 pw.println("Permission Denial: can't dump DisplayManager from from pid=" 563 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 564 return; 565 } 566 567 pw.println("DISPLAY MANAGER (dumpsys display)"); 568 pw.println(" mHeadless=" + mHeadless); 569 570 synchronized (mSyncRoot) { 571 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 572 ipw.increaseIndent(); 573 574 pw.println(); 575 pw.println("Display Adapters: size=" + mDisplayAdapters.size()); 576 for (DisplayAdapter adapter : mDisplayAdapters) { 577 pw.println(" " + adapter.getName()); 578 adapter.dumpLocked(ipw); 579 } 580 581 pw.println(); 582 pw.println("Display Devices: size=" + mDisplayDevices.size()); 583 for (DisplayDevice device : mDisplayDevices) { 584 pw.println(" " + device.getDisplayDeviceInfoLocked()); 585 device.dumpLocked(ipw); 586 } 587 588 final int logicalDisplayCount = mLogicalDisplays.size(); 589 pw.println(); 590 pw.println("Logical Displays: size=" + logicalDisplayCount); 591 for (int i = 0; i < logicalDisplayCount; i++) { 592 int displayId = mLogicalDisplays.keyAt(i); 593 LogicalDisplay display = mLogicalDisplays.valueAt(i); 594 pw.println(" Display " + displayId + ":"); 595 display.dumpLocked(ipw); 596 } 597 } 598 } 599 600 /** 601 * This is the object that everything in the display manager locks on. 602 * We make it an inner class within the {@link DisplayManagerService} to so that it is 603 * clear that the object belongs to the display manager service and that it is 604 * a unique object with a special purpose. 605 */ 606 public static final class SyncRoot { 607 } 608 609 /** 610 * Private interface to the window manager. 611 */ 612 public interface WindowManagerFuncs { 613 /** 614 * Request that the window manager call {@link #performTraversalInTransaction} 615 * within a surface transaction at a later time. 616 */ 617 void requestTraversal(); 618 } 619 620 private final class DisplayManagerHandler extends Handler { 621 public DisplayManagerHandler(Looper looper) { 622 super(looper, null, true /*async*/); 623 } 624 625 @Override 626 public void handleMessage(Message msg) { 627 switch (msg.what) { 628 case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER: 629 registerDefaultDisplayAdapter(); 630 break; 631 632 case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS: 633 registerAdditionalDisplayAdapters(); 634 break; 635 636 case MSG_DELIVER_DISPLAY_EVENT: 637 deliverDisplayEvent(msg.arg1, msg.arg2); 638 break; 639 640 case MSG_REQUEST_TRAVERSAL: 641 mWindowManagerFuncs.requestTraversal(); 642 break; 643 } 644 } 645 } 646 647 private final class DisplayAdapterListener implements DisplayAdapter.Listener { 648 @Override 649 public void onDisplayDeviceEvent(DisplayDevice device, int event) { 650 switch (event) { 651 case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED: 652 handleDisplayDeviceAdded(device); 653 break; 654 655 case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED: 656 handleDisplayDeviceChanged(device); 657 break; 658 659 case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED: 660 handleDisplayDeviceRemoved(device); 661 break; 662 } 663 } 664 665 @Override 666 public void onTraversalRequested() { 667 synchronized (mSyncRoot) { 668 scheduleTraversalLocked(); 669 } 670 } 671 } 672 673 private final class CallbackRecord implements DeathRecipient { 674 private final int mPid; 675 private final IDisplayManagerCallback mCallback; 676 677 public CallbackRecord(int pid, IDisplayManagerCallback callback) { 678 mPid = pid; 679 mCallback = callback; 680 } 681 682 @Override 683 public void binderDied() { 684 if (DEBUG) { 685 Slog.d(TAG, "Display listener for pid " + mPid + " died."); 686 } 687 onCallbackDied(mPid); 688 } 689 690 public void notifyDisplayEventAsync(int displayId, int event) { 691 try { 692 mCallback.onDisplayEvent(displayId, event); 693 } catch (RemoteException ex) { 694 Slog.w(TAG, "Failed to notify process " 695 + mPid + " that displays changed, assuming it died.", ex); 696 binderDied(); 697 } 698 } 699 } 700} 701