DisplayManagerService.java revision 4ed8fe75e1dde1a2b9576f3862aecc5a572c56b5
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 } 337 } 338 } 339 340 private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() { 341 // In safe mode, we disable non-essential display adapters to give the user 342 // an opportunity to fix broken settings or other problems that might affect 343 // system stability. 344 // In only-core mode, we disable non-essential display adapters to minimize 345 // the number of dependencies that are started while in this mode and to 346 // prevent problems that might occur due to the device being encrypted. 347 return !mSafeMode && !mOnlyCore; 348 } 349 350 private void registerDisplayAdapterLocked(DisplayAdapter adapter) { 351 mDisplayAdapters.add(adapter); 352 adapter.registerLocked(); 353 } 354 355 private void handleDisplayDeviceAdded(DisplayDevice device) { 356 synchronized (mSyncRoot) { 357 if (mDisplayDevices.contains(device)) { 358 Slog.w(TAG, "Attempted to add already added display device: " 359 + device.getDisplayDeviceInfoLocked()); 360 return; 361 } 362 363 mDisplayDevices.add(device); 364 addLogicalDisplayLocked(device); 365 scheduleTraversalLocked(); 366 } 367 } 368 369 private void handleDisplayDeviceChanged(DisplayDevice device) { 370 synchronized (mSyncRoot) { 371 if (!mDisplayDevices.contains(device)) { 372 Slog.w(TAG, "Attempted to change non-existent display device: " 373 + device.getDisplayDeviceInfoLocked()); 374 return; 375 } 376 377 device.applyPendingDisplayDeviceInfoChangesLocked(); 378 if (updateLogicalDisplaysLocked()) { 379 scheduleTraversalLocked(); 380 } 381 } 382 } 383 384 private void handleDisplayDeviceRemoved(DisplayDevice device) { 385 synchronized (mSyncRoot) { 386 if (!mDisplayDevices.remove(device)) { 387 Slog.w(TAG, "Attempted to remove non-existent display device: " 388 + device.getDisplayDeviceInfoLocked()); 389 return; 390 } 391 392 mRemovedDisplayDevices.add(device); 393 updateLogicalDisplaysLocked(); 394 scheduleTraversalLocked(); 395 } 396 } 397 398 // Adds a new logical display based on the given display device. 399 // Sends notifications if needed. 400 private void addLogicalDisplayLocked(DisplayDevice device) { 401 DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); 402 boolean isDefault = (deviceInfo.flags 403 & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0; 404 if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) { 405 Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo); 406 isDefault = false; 407 } 408 409 final int displayId = assignDisplayIdLocked(isDefault); 410 final int layerStack = assignLayerStackLocked(displayId); 411 412 LogicalDisplay display = new LogicalDisplay(layerStack, device); 413 display.updateLocked(mDisplayDevices); 414 if (!display.isValidLocked()) { 415 // This should never happen currently. 416 Slog.w(TAG, "Ignoring display device because the logical display " 417 + "created from it was not considered valid: " + deviceInfo); 418 return; 419 } 420 421 mLogicalDisplays.put(displayId, display); 422 423 // Wake up waitForDefaultDisplay. 424 if (isDefault) { 425 mSyncRoot.notifyAll(); 426 } 427 428 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED); 429 } 430 431 private int assignDisplayIdLocked(boolean isDefault) { 432 return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++; 433 } 434 435 private int assignLayerStackLocked(int displayId) { 436 // Currently layer stacks and display ids are the same. 437 // This need not be the case. 438 return displayId; 439 } 440 441 // Updates all existing logical displays given the current set of display devices. 442 // Removes invalid logical displays. 443 // Sends notifications if needed. 444 private boolean updateLogicalDisplaysLocked() { 445 boolean changed = false; 446 for (int i = mLogicalDisplays.size(); i-- > 0; ) { 447 final int displayId = mLogicalDisplays.keyAt(i); 448 LogicalDisplay display = mLogicalDisplays.valueAt(i); 449 450 mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked()); 451 display.updateLocked(mDisplayDevices); 452 if (!display.isValidLocked()) { 453 mLogicalDisplays.removeAt(i); 454 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); 455 changed = true; 456 } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) { 457 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); 458 changed = true; 459 } 460 } 461 return changed; 462 } 463 464 private void performTraversalInTransactionLocked() { 465 // Perform one last traversal for each removed display device. 466 final int removedCount = mRemovedDisplayDevices.size(); 467 for (int i = 0; i < removedCount; i++) { 468 DisplayDevice device = mRemovedDisplayDevices.get(i); 469 device.performTraversalInTransactionLocked(); 470 } 471 mRemovedDisplayDevices.clear(); 472 473 // Configure each display device. 474 final int count = mDisplayDevices.size(); 475 for (int i = 0; i < count; i++) { 476 DisplayDevice device = mDisplayDevices.get(i); 477 configureDisplayInTransactionLocked(device); 478 device.performTraversalInTransactionLocked(); 479 } 480 } 481 482 private void configureDisplayInTransactionLocked(DisplayDevice device) { 483 // TODO: add a proper per-display mirroring control 484 boolean isMirroring = SystemProperties.getBoolean("debug.display.mirror", true); 485 486 // Find the logical display that the display device is showing. 487 LogicalDisplay display = null; 488 if (!isMirroring) { 489 display = findLogicalDisplayForDeviceLocked(device); 490 } 491 if (display == null) { 492 display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY); 493 } 494 495 // Apply the logical display configuration to the display device. 496 if (display == null) { 497 // TODO: no logical display for the device, blank it 498 Slog.d(TAG, "Missing logical display to use for physical display device: " 499 + device.getDisplayDeviceInfoLocked()); 500 } else { 501 display.configureDisplayInTransactionLocked(device); 502 } 503 } 504 505 private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) { 506 final int count = mLogicalDisplays.size(); 507 for (int i = 0; i < count; i++) { 508 LogicalDisplay display = mLogicalDisplays.valueAt(i); 509 if (display.getPrimaryDisplayDeviceLocked() == device) { 510 return display; 511 } 512 } 513 return null; 514 } 515 516 private void sendDisplayEventLocked(int displayId, int event) { 517 Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event); 518 mHandler.sendMessage(msg); 519 } 520 521 // Requests that performTraversalsInTransactionFromWindowManager be called at a 522 // later time to apply changes to surfaces and displays. 523 private void scheduleTraversalLocked() { 524 if (!mPendingTraversal && mWindowManagerFuncs != null) { 525 mPendingTraversal = true; 526 mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL); 527 } 528 } 529 530 // Runs on Handler thread. 531 // Delivers display event notifications to callbacks. 532 private void deliverDisplayEvent(int displayId, int event) { 533 if (DEBUG) { 534 Slog.d(TAG, "Delivering display event: displayId=" 535 + displayId + ", event=" + event); 536 } 537 538 // Grab the lock and copy the callbacks. 539 final int count; 540 synchronized (mSyncRoot) { 541 count = mCallbacks.size(); 542 mTempCallbacks.clear(); 543 for (int i = 0; i < count; i++) { 544 mTempCallbacks.add(mCallbacks.valueAt(i)); 545 } 546 } 547 548 // After releasing the lock, send the notifications out. 549 for (int i = 0; i < count; i++) { 550 mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event); 551 } 552 mTempCallbacks.clear(); 553 } 554 555 @Override // Binder call 556 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 557 if (mContext == null 558 || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 559 != PackageManager.PERMISSION_GRANTED) { 560 pw.println("Permission Denial: can't dump DisplayManager from from pid=" 561 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 562 return; 563 } 564 565 pw.println("DISPLAY MANAGER (dumpsys display)"); 566 pw.println(" mHeadless=" + mHeadless); 567 568 synchronized (mSyncRoot) { 569 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 570 ipw.increaseIndent(); 571 572 pw.println(); 573 pw.println("Display Adapters: size=" + mDisplayAdapters.size()); 574 for (DisplayAdapter adapter : mDisplayAdapters) { 575 pw.println(" " + adapter.getName()); 576 adapter.dumpLocked(ipw); 577 } 578 579 pw.println(); 580 pw.println("Display Devices: size=" + mDisplayDevices.size()); 581 for (DisplayDevice device : mDisplayDevices) { 582 pw.println(" " + device.getDisplayDeviceInfoLocked()); 583 device.dumpLocked(ipw); 584 } 585 586 final int logicalDisplayCount = mLogicalDisplays.size(); 587 pw.println(); 588 pw.println("Logical Displays: size=" + logicalDisplayCount); 589 for (int i = 0; i < logicalDisplayCount; i++) { 590 int displayId = mLogicalDisplays.keyAt(i); 591 LogicalDisplay display = mLogicalDisplays.valueAt(i); 592 pw.println(" Display " + displayId + ":"); 593 display.dumpLocked(ipw); 594 } 595 } 596 } 597 598 /** 599 * This is the object that everything in the display manager locks on. 600 * We make it an inner class within the {@link DisplayManagerService} to so that it is 601 * clear that the object belongs to the display manager service and that it is 602 * a unique object with a special purpose. 603 */ 604 public static final class SyncRoot { 605 } 606 607 /** 608 * Private interface to the window manager. 609 */ 610 public interface WindowManagerFuncs { 611 /** 612 * Request that the window manager call {@link #performTraversalInTransaction} 613 * within a surface transaction at a later time. 614 */ 615 void requestTraversal(); 616 } 617 618 private final class DisplayManagerHandler extends Handler { 619 public DisplayManagerHandler(Looper looper) { 620 super(looper, null, true /*async*/); 621 } 622 623 @Override 624 public void handleMessage(Message msg) { 625 switch (msg.what) { 626 case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER: 627 registerDefaultDisplayAdapter(); 628 break; 629 630 case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS: 631 registerAdditionalDisplayAdapters(); 632 break; 633 634 case MSG_DELIVER_DISPLAY_EVENT: 635 deliverDisplayEvent(msg.arg1, msg.arg2); 636 break; 637 638 case MSG_REQUEST_TRAVERSAL: 639 mWindowManagerFuncs.requestTraversal(); 640 break; 641 } 642 } 643 } 644 645 private final class DisplayAdapterListener implements DisplayAdapter.Listener { 646 @Override 647 public void onDisplayDeviceEvent(DisplayDevice device, int event) { 648 switch (event) { 649 case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED: 650 handleDisplayDeviceAdded(device); 651 break; 652 653 case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED: 654 handleDisplayDeviceChanged(device); 655 break; 656 657 case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED: 658 handleDisplayDeviceRemoved(device); 659 break; 660 } 661 } 662 663 @Override 664 public void onTraversalRequested() { 665 synchronized (mSyncRoot) { 666 scheduleTraversalLocked(); 667 } 668 } 669 } 670 671 private final class CallbackRecord implements DeathRecipient { 672 private final int mPid; 673 private final IDisplayManagerCallback mCallback; 674 675 public CallbackRecord(int pid, IDisplayManagerCallback callback) { 676 mPid = pid; 677 mCallback = callback; 678 } 679 680 @Override 681 public void binderDied() { 682 if (DEBUG) { 683 Slog.d(TAG, "Display listener for pid " + mPid + " died."); 684 } 685 onCallbackDied(mPid); 686 } 687 688 public void notifyDisplayEventAsync(int displayId, int event) { 689 try { 690 mCallback.onDisplayEvent(displayId, event); 691 } catch (RemoteException ex) { 692 Slog.w(TAG, "Failed to notify process " 693 + mPid + " that displays changed, assuming it died.", ex); 694 binderDied(); 695 } 696 } 697 } 698} 699