DisplayManagerService.java revision 722285e199a9fc74b9b3343b7505c00666848c88
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.Listener} 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 * @return The logical display info, or null if the display does not exist. The 258 * returned 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 /** 485 * Tells the display manager whether there is interesting unique content on the 486 * specified logical display. This is used to control automatic mirroring. 487 * <p> 488 * If the display has unique content, then the display manager arranges for it 489 * to be presented on a physical display if appropriate. Otherwise, the display manager 490 * may choose to make the physical display mirror some other logical display. 491 * </p> 492 * 493 * @param displayId The logical display id to update. 494 * @param hasContent True if the logical display has content. 495 */ 496 public void setDisplayHasContent(int displayId, boolean hasContent) { 497 synchronized (mSyncRoot) { 498 LogicalDisplay display = mLogicalDisplays.get(displayId); 499 if (display != null && display.hasContentLocked() != hasContent) { 500 display.setHasContentLocked(hasContent); 501 scheduleTraversalLocked(); 502 } 503 } 504 505 } 506 507 private void configureDisplayInTransactionLocked(DisplayDevice device) { 508 // Find the logical display that the display device is showing. 509 LogicalDisplay display = findLogicalDisplayForDeviceLocked(device); 510 if (display != null && !display.hasContentLocked()) { 511 display = null; 512 } 513 if (display == null) { 514 display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY); 515 } 516 517 // Apply the logical display configuration to the display device. 518 if (display == null) { 519 // TODO: no logical display for the device, blank it 520 Slog.d(TAG, "Missing logical display to use for physical display device: " 521 + device.getDisplayDeviceInfoLocked()); 522 } else { 523 display.configureDisplayInTransactionLocked(device); 524 } 525 } 526 527 private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) { 528 final int count = mLogicalDisplays.size(); 529 for (int i = 0; i < count; i++) { 530 LogicalDisplay display = mLogicalDisplays.valueAt(i); 531 if (display.getPrimaryDisplayDeviceLocked() == device) { 532 return display; 533 } 534 } 535 return null; 536 } 537 538 private void sendDisplayEventLocked(int displayId, int event) { 539 Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event); 540 mHandler.sendMessage(msg); 541 } 542 543 // Requests that performTraversalsInTransactionFromWindowManager be called at a 544 // later time to apply changes to surfaces and displays. 545 private void scheduleTraversalLocked() { 546 if (!mPendingTraversal && mWindowManagerFuncs != null) { 547 mPendingTraversal = true; 548 mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL); 549 } 550 } 551 552 // Runs on Handler thread. 553 // Delivers display event notifications to callbacks. 554 private void deliverDisplayEvent(int displayId, int event) { 555 if (DEBUG) { 556 Slog.d(TAG, "Delivering display event: displayId=" 557 + displayId + ", event=" + event); 558 } 559 560 // Grab the lock and copy the callbacks. 561 final int count; 562 synchronized (mSyncRoot) { 563 count = mCallbacks.size(); 564 mTempCallbacks.clear(); 565 for (int i = 0; i < count; i++) { 566 mTempCallbacks.add(mCallbacks.valueAt(i)); 567 } 568 } 569 570 // After releasing the lock, send the notifications out. 571 for (int i = 0; i < count; i++) { 572 mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event); 573 } 574 mTempCallbacks.clear(); 575 } 576 577 @Override // Binder call 578 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 579 if (mContext == null 580 || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 581 != PackageManager.PERMISSION_GRANTED) { 582 pw.println("Permission Denial: can't dump DisplayManager from from pid=" 583 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 584 return; 585 } 586 587 pw.println("DISPLAY MANAGER (dumpsys display)"); 588 pw.println(" mHeadless=" + mHeadless); 589 590 synchronized (mSyncRoot) { 591 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 592 ipw.increaseIndent(); 593 594 pw.println(); 595 pw.println("Display Adapters: size=" + mDisplayAdapters.size()); 596 for (DisplayAdapter adapter : mDisplayAdapters) { 597 pw.println(" " + adapter.getName()); 598 adapter.dumpLocked(ipw); 599 } 600 601 pw.println(); 602 pw.println("Display Devices: size=" + mDisplayDevices.size()); 603 for (DisplayDevice device : mDisplayDevices) { 604 pw.println(" " + device.getDisplayDeviceInfoLocked()); 605 device.dumpLocked(ipw); 606 } 607 608 final int logicalDisplayCount = mLogicalDisplays.size(); 609 pw.println(); 610 pw.println("Logical Displays: size=" + logicalDisplayCount); 611 for (int i = 0; i < logicalDisplayCount; i++) { 612 int displayId = mLogicalDisplays.keyAt(i); 613 LogicalDisplay display = mLogicalDisplays.valueAt(i); 614 pw.println(" Display " + displayId + ":"); 615 display.dumpLocked(ipw); 616 } 617 } 618 } 619 620 /** 621 * This is the object that everything in the display manager locks on. 622 * We make it an inner class within the {@link DisplayManagerService} to so that it is 623 * clear that the object belongs to the display manager service and that it is 624 * a unique object with a special purpose. 625 */ 626 public static final class SyncRoot { 627 } 628 629 /** 630 * Private interface to the window manager. 631 */ 632 public interface WindowManagerFuncs { 633 /** 634 * Request that the window manager call 635 * {@link #performTraversalInTransactionFromWindowManager} within a surface 636 * transaction at a later time. 637 */ 638 void requestTraversal(); 639 } 640 641 private final class DisplayManagerHandler extends Handler { 642 public DisplayManagerHandler(Looper looper) { 643 super(looper, null, true /*async*/); 644 } 645 646 @Override 647 public void handleMessage(Message msg) { 648 switch (msg.what) { 649 case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER: 650 registerDefaultDisplayAdapter(); 651 break; 652 653 case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS: 654 registerAdditionalDisplayAdapters(); 655 break; 656 657 case MSG_DELIVER_DISPLAY_EVENT: 658 deliverDisplayEvent(msg.arg1, msg.arg2); 659 break; 660 661 case MSG_REQUEST_TRAVERSAL: 662 mWindowManagerFuncs.requestTraversal(); 663 break; 664 } 665 } 666 } 667 668 private final class DisplayAdapterListener implements DisplayAdapter.Listener { 669 @Override 670 public void onDisplayDeviceEvent(DisplayDevice device, int event) { 671 switch (event) { 672 case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED: 673 handleDisplayDeviceAdded(device); 674 break; 675 676 case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED: 677 handleDisplayDeviceChanged(device); 678 break; 679 680 case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED: 681 handleDisplayDeviceRemoved(device); 682 break; 683 } 684 } 685 686 @Override 687 public void onTraversalRequested() { 688 synchronized (mSyncRoot) { 689 scheduleTraversalLocked(); 690 } 691 } 692 } 693 694 private final class CallbackRecord implements DeathRecipient { 695 private final int mPid; 696 private final IDisplayManagerCallback mCallback; 697 698 public CallbackRecord(int pid, IDisplayManagerCallback callback) { 699 mPid = pid; 700 mCallback = callback; 701 } 702 703 @Override 704 public void binderDied() { 705 if (DEBUG) { 706 Slog.d(TAG, "Display listener for pid " + mPid + " died."); 707 } 708 onCallbackDied(mPid); 709 } 710 711 public void notifyDisplayEventAsync(int displayId, int event) { 712 try { 713 mCallback.onDisplayEvent(displayId, event); 714 } catch (RemoteException ex) { 715 Slog.w(TAG, "Failed to notify process " 716 + mPid + " that displays changed, assuming it died.", ex); 717 binderDied(); 718 } 719 } 720 } 721} 722