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