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