DisplayManagerService.java revision e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9
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.hardware.display.WifiDisplayStatus;
28import android.os.Binder;
29import android.os.Handler;
30import android.os.IBinder;
31import android.os.Looper;
32import android.os.Message;
33import android.os.RemoteException;
34import android.os.SystemClock;
35import android.os.SystemProperties;
36import android.util.Slog;
37import android.util.SparseArray;
38import android.view.Display;
39import android.view.DisplayInfo;
40
41import java.io.FileDescriptor;
42import java.io.PrintWriter;
43import java.util.ArrayList;
44
45/**
46 * Manages attached displays.
47 * <p>
48 * The {@link DisplayManagerService} manages the global lifecycle of displays,
49 * decides how to configure logical displays based on the physical display devices currently
50 * attached, sends notifications to the system and to applications when the state
51 * changes, and so on.
52 * </p><p>
53 * The display manager service relies on a collection of {@link DisplayAdapter} components,
54 * for discovering and configuring physical display devices attached to the system.
55 * There are separate display adapters for each manner that devices are attached:
56 * one display adapter for built-in local displays, one for simulated non-functional
57 * displays when the system is headless, one for simulated overlay displays used for
58 * development, one for wifi displays, etc.
59 * </p><p>
60 * Display adapters are only weakly coupled to the display manager service.
61 * Display adapters communicate changes in display device state to the display manager
62 * service asynchronously via a {@link DisplayAdapter.Listener} registered
63 * by the display manager service.  This separation of concerns is important for
64 * two main reasons.  First, it neatly encapsulates the responsibilities of these
65 * two classes: display adapters handle individual display devices whereas
66 * the display manager service handles the global state.  Second, it eliminates
67 * the potential for deadlocks resulting from asynchronous display device discovery.
68 * </p>
69 *
70 * <h3>Synchronization</h3>
71 * <p>
72 * Because the display manager may be accessed by multiple threads, the synchronization
73 * story gets a little complicated.  In particular, the window manager may call into
74 * the display manager while holding a surface transaction with the expectation that
75 * it can apply changes immediately.  Unfortunately, that means we can't just do
76 * everything asynchronously (*grump*).
77 * </p><p>
78 * To make this work, all of the objects that belong to the display manager must
79 * use the same lock.  We call this lock the synchronization root and it has a unique
80 * type {@link DisplayManagerService.SyncRoot}.  Methods that require this lock are
81 * named with the "Locked" suffix.
82 * </p><p>
83 * Where things get tricky is that the display manager is not allowed to make
84 * any potentially reentrant calls, especially into the window manager.  We generally
85 * avoid this by making all potentially reentrant out-calls asynchronous.
86 * </p>
87 */
88public final class DisplayManagerService extends IDisplayManager.Stub {
89    private static final String TAG = "DisplayManagerService";
90    private static final boolean DEBUG = false;
91
92    private static final String SYSTEM_HEADLESS = "ro.config.headless";
93    private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
94
95    private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1;
96    private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
97    private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
98    private static final int MSG_REQUEST_TRAVERSAL = 4;
99
100    private final Context mContext;
101    private final boolean mHeadless;
102    private final DisplayManagerHandler mHandler;
103    private final Handler mUiHandler;
104    private final DisplayAdapterListener mDisplayAdapterListener;
105    private WindowManagerFuncs mWindowManagerFuncs;
106
107    // The synchronization root for the display manager.
108    // This lock guards most of the display manager's state.
109    private final SyncRoot mSyncRoot = new SyncRoot();
110
111    // True if in safe mode.
112    // This option may disable certain display adapters.
113    public boolean mSafeMode;
114
115    // True if we are in a special boot mode where only core applications and
116    // services should be started.  This option may disable certain display adapters.
117    public boolean mOnlyCore;
118
119    // All callback records indexed by calling process id.
120    public final SparseArray<CallbackRecord> mCallbacks =
121            new SparseArray<CallbackRecord>();
122
123    // List of all currently registered display adapters.
124    private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
125
126    // List of all currently connected display devices.
127    private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>();
128
129    // List of all removed display devices.
130    private final ArrayList<DisplayDevice> mRemovedDisplayDevices = new ArrayList<DisplayDevice>();
131
132    // List of all logical displays indexed by logical display id.
133    private final SparseArray<LogicalDisplay> mLogicalDisplays =
134            new SparseArray<LogicalDisplay>();
135    private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
136
137    // Set to true when there are pending display changes that have yet to be applied
138    // to the surface flinger state.
139    private boolean mPendingTraversal;
140
141    // The Wifi display adapter, or null if not registered.
142    private WifiDisplayAdapter mWifiDisplayAdapter;
143
144    // Temporary callback list, used when sending display events to applications.
145    // May be used outside of the lock but only on the handler thread.
146    private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
147
148    // Temporary display info, used for comparing display configurations.
149    private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
150
151    public DisplayManagerService(Context context, Handler mainHandler, Handler uiHandler) {
152        mContext = context;
153        mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
154
155        mHandler = new DisplayManagerHandler(mainHandler.getLooper());
156        mUiHandler = uiHandler;
157        mDisplayAdapterListener = new DisplayAdapterListener();
158
159        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
160    }
161
162    /**
163     * Pauses the boot process to wait for the first display to be initialized.
164     */
165    public boolean waitForDefaultDisplay() {
166        synchronized (mSyncRoot) {
167            long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
168            while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
169                long delay = timeout - SystemClock.uptimeMillis();
170                if (delay <= 0) {
171                    return false;
172                }
173                if (DEBUG) {
174                    Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
175                }
176                try {
177                    mSyncRoot.wait(delay);
178                } catch (InterruptedException ex) {
179                }
180            }
181        }
182        return true;
183    }
184
185    /**
186     * Called during initialization to associated the display manager with the
187     * window manager.
188     */
189    public void setWindowManager(WindowManagerFuncs windowManagerFuncs) {
190        synchronized (mSyncRoot) {
191            mWindowManagerFuncs = windowManagerFuncs;
192            scheduleTraversalLocked();
193        }
194    }
195
196    /**
197     * Called when the system is ready to go.
198     */
199    public void systemReady(boolean safeMode, boolean onlyCore) {
200        synchronized (mSyncRoot) {
201            mSafeMode = safeMode;
202            mOnlyCore = onlyCore;
203        }
204
205        mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
206    }
207
208    /**
209     * Returns true if the device is headless.
210     *
211     * @return True if the device is headless.
212     */
213    public boolean isHeadless() {
214        return mHeadless;
215    }
216
217    /**
218     * Overrides the display information of a particular logical display.
219     * This is used by the window manager to control the size and characteristics
220     * of the default display.  It is expected to apply the requested change
221     * to the display information synchronously so that applications will immediately
222     * observe the new state.
223     *
224     * @param displayId The logical display id.
225     * @param info The new data to be stored.
226     */
227    public void setDisplayInfoOverrideFromWindowManager(
228            int displayId, DisplayInfo info) {
229        synchronized (mSyncRoot) {
230            LogicalDisplay display = mLogicalDisplays.get(displayId);
231            if (display != null) {
232                mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
233                display.setDisplayInfoOverrideFromWindowManagerLocked(info);
234                if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
235                    sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
236                    scheduleTraversalLocked();
237                }
238            }
239        }
240    }
241
242    /**
243     * Called by the window manager to perform traversals while holding a
244     * surface flinger transaction.
245     */
246    public void performTraversalInTransactionFromWindowManager() {
247        synchronized (mSyncRoot) {
248            if (!mPendingTraversal) {
249                return;
250            }
251            mPendingTraversal = false;
252
253            performTraversalInTransactionLocked();
254        }
255    }
256
257    /**
258     * Returns information about the specified logical display.
259     *
260     * @param displayId The logical display id.
261     * @return The logical display info, or null if the display does not exist.  The
262     * returned object must be treated as immutable.
263     */
264    @Override // Binder call
265    public DisplayInfo getDisplayInfo(int displayId) {
266        synchronized (mSyncRoot) {
267            LogicalDisplay display = mLogicalDisplays.get(displayId);
268            if (display != null) {
269                return display.getDisplayInfoLocked();
270            }
271            return null;
272        }
273    }
274
275    /**
276     * Returns the list of all display ids.
277     */
278    @Override // Binder call
279    public int[] getDisplayIds() {
280        synchronized (mSyncRoot) {
281            final int count = mLogicalDisplays.size();
282            int[] displayIds = new int[count];
283            for (int i = 0; i < count; i++) {
284                displayIds[i] = mLogicalDisplays.keyAt(i);
285            }
286            return displayIds;
287        }
288    }
289
290    @Override // Binder call
291    public void registerCallback(IDisplayManagerCallback callback) {
292        if (callback == null) {
293            throw new IllegalArgumentException("listener must not be null");
294        }
295
296        synchronized (mSyncRoot) {
297            int callingPid = Binder.getCallingPid();
298            if (mCallbacks.get(callingPid) != null) {
299                throw new SecurityException("The calling process has already "
300                        + "registered an IDisplayManagerCallback.");
301            }
302
303            CallbackRecord record = new CallbackRecord(callingPid, callback);
304            try {
305                IBinder binder = callback.asBinder();
306                binder.linkToDeath(record, 0);
307            } catch (RemoteException ex) {
308                // give up
309                throw new RuntimeException(ex);
310            }
311
312            mCallbacks.put(callingPid, record);
313        }
314    }
315
316    private void onCallbackDied(int pid) {
317        synchronized (mSyncRoot) {
318            mCallbacks.remove(pid);
319        }
320    }
321
322    @Override // Binder call
323    public void scanWifiDisplays() {
324        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
325                != PackageManager.PERMISSION_GRANTED) {
326            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
327        }
328
329        final long token = Binder.clearCallingIdentity();
330        try {
331            synchronized (mSyncRoot) {
332                mWifiDisplayAdapter.requestScanLocked();
333            }
334        } finally {
335            Binder.restoreCallingIdentity(token);
336        }
337    }
338
339    @Override // Binder call
340    public void connectWifiDisplay(String address) {
341        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
342                != PackageManager.PERMISSION_GRANTED) {
343            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
344        }
345        if (address == null) {
346            throw new IllegalArgumentException("address must not be null");
347        }
348
349        final long token = Binder.clearCallingIdentity();
350        try {
351            synchronized (mSyncRoot) {
352                mWifiDisplayAdapter.requestConnectLocked(address);
353            }
354        } finally {
355            Binder.restoreCallingIdentity(token);
356        }
357    }
358
359    @Override // Binder call
360    public void disconnectWifiDisplay() {
361        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
362                != PackageManager.PERMISSION_GRANTED) {
363            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
364        }
365
366        final long token = Binder.clearCallingIdentity();
367        try {
368            synchronized (mSyncRoot) {
369                mWifiDisplayAdapter.requestDisconnectLocked();
370            }
371        } finally {
372            Binder.restoreCallingIdentity(token);
373        }
374    }
375
376    @Override // Binder call
377    public WifiDisplayStatus getWifiDisplayStatus() {
378        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
379                != PackageManager.PERMISSION_GRANTED) {
380            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
381        }
382
383        final long token = Binder.clearCallingIdentity();
384        try {
385            synchronized (mSyncRoot) {
386                return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
387            }
388        } finally {
389            Binder.restoreCallingIdentity(token);
390        }
391    }
392
393    private void registerDefaultDisplayAdapter() {
394        // Register default display adapter.
395        synchronized (mSyncRoot) {
396            if (mHeadless) {
397                registerDisplayAdapterLocked(new HeadlessDisplayAdapter(
398                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
399            } else {
400                registerDisplayAdapterLocked(new LocalDisplayAdapter(
401                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
402            }
403        }
404    }
405
406    private void registerAdditionalDisplayAdapters() {
407        synchronized (mSyncRoot) {
408            if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
409                registerDisplayAdapterLocked(new OverlayDisplayAdapter(
410                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
411                mWifiDisplayAdapter = new WifiDisplayAdapter(
412                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
413                registerDisplayAdapterLocked(mWifiDisplayAdapter);
414            }
415        }
416    }
417
418    private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
419        // In safe mode, we disable non-essential display adapters to give the user
420        // an opportunity to fix broken settings or other problems that might affect
421        // system stability.
422        // In only-core mode, we disable non-essential display adapters to minimize
423        // the number of dependencies that are started while in this mode and to
424        // prevent problems that might occur due to the device being encrypted.
425        return !mSafeMode && !mOnlyCore;
426    }
427
428    private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
429        mDisplayAdapters.add(adapter);
430        adapter.registerLocked();
431    }
432
433    private void handleDisplayDeviceAdded(DisplayDevice device) {
434        synchronized (mSyncRoot) {
435            if (mDisplayDevices.contains(device)) {
436                Slog.w(TAG, "Attempted to add already added display device: "
437                        + device.getDisplayDeviceInfoLocked());
438                return;
439            }
440
441            mDisplayDevices.add(device);
442            addLogicalDisplayLocked(device);
443            scheduleTraversalLocked();
444        }
445    }
446
447    private void handleDisplayDeviceChanged(DisplayDevice device) {
448        synchronized (mSyncRoot) {
449            if (!mDisplayDevices.contains(device)) {
450                Slog.w(TAG, "Attempted to change non-existent display device: "
451                        + device.getDisplayDeviceInfoLocked());
452                return;
453            }
454
455            device.applyPendingDisplayDeviceInfoChangesLocked();
456            if (updateLogicalDisplaysLocked()) {
457                scheduleTraversalLocked();
458            }
459        }
460    }
461
462    private void handleDisplayDeviceRemoved(DisplayDevice device) {
463        synchronized (mSyncRoot) {
464            if (!mDisplayDevices.remove(device)) {
465                Slog.w(TAG, "Attempted to remove non-existent display device: "
466                        + device.getDisplayDeviceInfoLocked());
467                return;
468            }
469
470            mRemovedDisplayDevices.add(device);
471            updateLogicalDisplaysLocked();
472            scheduleTraversalLocked();
473        }
474    }
475
476    // Adds a new logical display based on the given display device.
477    // Sends notifications if needed.
478    private void addLogicalDisplayLocked(DisplayDevice device) {
479        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
480        boolean isDefault = (deviceInfo.flags
481                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
482        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
483            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
484            isDefault = false;
485        }
486
487        final int displayId = assignDisplayIdLocked(isDefault);
488        final int layerStack = assignLayerStackLocked(displayId);
489
490        LogicalDisplay display = new LogicalDisplay(layerStack, device);
491        display.updateLocked(mDisplayDevices);
492        if (!display.isValidLocked()) {
493            // This should never happen currently.
494            Slog.w(TAG, "Ignoring display device because the logical display "
495                    + "created from it was not considered valid: " + deviceInfo);
496            return;
497        }
498
499        mLogicalDisplays.put(displayId, display);
500
501        // Wake up waitForDefaultDisplay.
502        if (isDefault) {
503            mSyncRoot.notifyAll();
504        }
505
506        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
507    }
508
509    private int assignDisplayIdLocked(boolean isDefault) {
510        return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
511    }
512
513    private int assignLayerStackLocked(int displayId) {
514        // Currently layer stacks and display ids are the same.
515        // This need not be the case.
516        return displayId;
517    }
518
519    // Updates all existing logical displays given the current set of display devices.
520    // Removes invalid logical displays.
521    // Sends notifications if needed.
522    private boolean updateLogicalDisplaysLocked() {
523        boolean changed = false;
524        for (int i = mLogicalDisplays.size(); i-- > 0; ) {
525            final int displayId = mLogicalDisplays.keyAt(i);
526            LogicalDisplay display = mLogicalDisplays.valueAt(i);
527
528            mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
529            display.updateLocked(mDisplayDevices);
530            if (!display.isValidLocked()) {
531                mLogicalDisplays.removeAt(i);
532                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
533                changed = true;
534            } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
535                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
536                changed = true;
537            }
538        }
539        return changed;
540    }
541
542    private void performTraversalInTransactionLocked() {
543        // Perform one last traversal for each removed display device.
544        final int removedCount = mRemovedDisplayDevices.size();
545        for (int i = 0; i < removedCount; i++) {
546            DisplayDevice device = mRemovedDisplayDevices.get(i);
547            device.performTraversalInTransactionLocked();
548        }
549        mRemovedDisplayDevices.clear();
550
551        // Configure each display device.
552        final int count = mDisplayDevices.size();
553        for (int i = 0; i < count; i++) {
554            DisplayDevice device = mDisplayDevices.get(i);
555            configureDisplayInTransactionLocked(device);
556            device.performTraversalInTransactionLocked();
557        }
558    }
559
560    /**
561     * Tells the display manager whether there is interesting unique content on the
562     * specified logical display.  This is used to control automatic mirroring.
563     * <p>
564     * If the display has unique content, then the display manager arranges for it
565     * to be presented on a physical display if appropriate.  Otherwise, the display manager
566     * may choose to make the physical display mirror some other logical display.
567     * </p>
568     *
569     * @param displayId The logical display id to update.
570     * @param hasContent True if the logical display has content.
571     */
572    public void setDisplayHasContent(int displayId, boolean hasContent) {
573        synchronized (mSyncRoot) {
574            LogicalDisplay display = mLogicalDisplays.get(displayId);
575            if (display != null && display.hasContentLocked() != hasContent) {
576                display.setHasContentLocked(hasContent);
577                scheduleTraversalLocked();
578            }
579        }
580
581    }
582
583    private void configureDisplayInTransactionLocked(DisplayDevice device) {
584        // Find the logical display that the display device is showing.
585        LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
586        if (display != null && !display.hasContentLocked()) {
587            display = null;
588        }
589        if (display == null) {
590            display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
591        }
592
593        // Apply the logical display configuration to the display device.
594        if (display == null) {
595            // TODO: no logical display for the device, blank it
596            Slog.d(TAG, "Missing logical display to use for physical display device: "
597                    + device.getDisplayDeviceInfoLocked());
598        } else {
599            display.configureDisplayInTransactionLocked(device);
600        }
601    }
602
603    private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) {
604        final int count = mLogicalDisplays.size();
605        for (int i = 0; i < count; i++) {
606            LogicalDisplay display = mLogicalDisplays.valueAt(i);
607            if (display.getPrimaryDisplayDeviceLocked() == device) {
608                return display;
609            }
610        }
611        return null;
612    }
613
614    private void sendDisplayEventLocked(int displayId, int event) {
615        Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
616        mHandler.sendMessage(msg);
617    }
618
619    // Requests that performTraversalsInTransactionFromWindowManager be called at a
620    // later time to apply changes to surfaces and displays.
621    private void scheduleTraversalLocked() {
622        if (!mPendingTraversal && mWindowManagerFuncs != null) {
623            mPendingTraversal = true;
624            mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
625        }
626    }
627
628    // Runs on Handler thread.
629    // Delivers display event notifications to callbacks.
630    private void deliverDisplayEvent(int displayId, int event) {
631        if (DEBUG) {
632            Slog.d(TAG, "Delivering display event: displayId="
633                    + displayId + ", event=" + event);
634        }
635
636        // Grab the lock and copy the callbacks.
637        final int count;
638        synchronized (mSyncRoot) {
639            count = mCallbacks.size();
640            mTempCallbacks.clear();
641            for (int i = 0; i < count; i++) {
642                mTempCallbacks.add(mCallbacks.valueAt(i));
643            }
644        }
645
646        // After releasing the lock, send the notifications out.
647        for (int i = 0; i < count; i++) {
648            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
649        }
650        mTempCallbacks.clear();
651    }
652
653    @Override // Binder call
654    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
655        if (mContext == null
656                || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
657                        != PackageManager.PERMISSION_GRANTED) {
658            pw.println("Permission Denial: can't dump DisplayManager from from pid="
659                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
660            return;
661        }
662
663        pw.println("DISPLAY MANAGER (dumpsys display)");
664        pw.println("  mHeadless=" + mHeadless);
665
666        synchronized (mSyncRoot) {
667            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
668            ipw.increaseIndent();
669
670            pw.println();
671            pw.println("Display Adapters: size=" + mDisplayAdapters.size());
672            for (DisplayAdapter adapter : mDisplayAdapters) {
673                pw.println("  " + adapter.getName());
674                adapter.dumpLocked(ipw);
675            }
676
677            pw.println();
678            pw.println("Display Devices: size=" + mDisplayDevices.size());
679            for (DisplayDevice device : mDisplayDevices) {
680                pw.println("  " + device.getDisplayDeviceInfoLocked());
681                device.dumpLocked(ipw);
682            }
683
684            final int logicalDisplayCount = mLogicalDisplays.size();
685            pw.println();
686            pw.println("Logical Displays: size=" + logicalDisplayCount);
687            for (int i = 0; i < logicalDisplayCount; i++) {
688                int displayId = mLogicalDisplays.keyAt(i);
689                LogicalDisplay display = mLogicalDisplays.valueAt(i);
690                pw.println("  Display " + displayId + ":");
691                display.dumpLocked(ipw);
692            }
693        }
694    }
695
696    /**
697     * This is the object that everything in the display manager locks on.
698     * We make it an inner class within the {@link DisplayManagerService} to so that it is
699     * clear that the object belongs to the display manager service and that it is
700     * a unique object with a special purpose.
701     */
702    public static final class SyncRoot {
703    }
704
705    /**
706     * Private interface to the window manager.
707     */
708    public interface WindowManagerFuncs {
709        /**
710         * Request that the window manager call
711         * {@link #performTraversalInTransactionFromWindowManager} within a surface
712         * transaction at a later time.
713         */
714        void requestTraversal();
715    }
716
717    private final class DisplayManagerHandler extends Handler {
718        public DisplayManagerHandler(Looper looper) {
719            super(looper, null, true /*async*/);
720        }
721
722        @Override
723        public void handleMessage(Message msg) {
724            switch (msg.what) {
725                case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
726                    registerDefaultDisplayAdapter();
727                    break;
728
729                case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
730                    registerAdditionalDisplayAdapters();
731                    break;
732
733                case MSG_DELIVER_DISPLAY_EVENT:
734                    deliverDisplayEvent(msg.arg1, msg.arg2);
735                    break;
736
737                case MSG_REQUEST_TRAVERSAL:
738                    mWindowManagerFuncs.requestTraversal();
739                    break;
740            }
741        }
742    }
743
744    private final class DisplayAdapterListener implements DisplayAdapter.Listener {
745        @Override
746        public void onDisplayDeviceEvent(DisplayDevice device, int event) {
747            switch (event) {
748                case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
749                    handleDisplayDeviceAdded(device);
750                    break;
751
752                case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
753                    handleDisplayDeviceChanged(device);
754                    break;
755
756                case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
757                    handleDisplayDeviceRemoved(device);
758                    break;
759            }
760        }
761
762        @Override
763        public void onTraversalRequested() {
764            synchronized (mSyncRoot) {
765                scheduleTraversalLocked();
766            }
767        }
768    }
769
770    private final class CallbackRecord implements DeathRecipient {
771        private final int mPid;
772        private final IDisplayManagerCallback mCallback;
773
774        public CallbackRecord(int pid, IDisplayManagerCallback callback) {
775            mPid = pid;
776            mCallback = callback;
777        }
778
779        @Override
780        public void binderDied() {
781            if (DEBUG) {
782                Slog.d(TAG, "Display listener for pid " + mPid + " died.");
783            }
784            onCallbackDied(mPid);
785        }
786
787        public void notifyDisplayEventAsync(int displayId, int event) {
788            try {
789                mCallback.onDisplayEvent(displayId, event);
790            } catch (RemoteException ex) {
791                Slog.w(TAG, "Failed to notify process "
792                        + mPid + " that displays changed, assuming it died.", ex);
793                binderDied();
794            }
795        }
796    }
797}
798