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