DisplayManagerService.java revision 89d5546d7fd3a3bb19820c42e8b4527013dd6545
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    private static final int MSG_UPDATE_VIEWPORT = 5;
100
101    private final Context mContext;
102    private final boolean mHeadless;
103    private final DisplayManagerHandler mHandler;
104    private final Handler mUiHandler;
105    private final DisplayAdapterListener mDisplayAdapterListener;
106    private WindowManagerFuncs mWindowManagerFuncs;
107    private InputManagerFuncs mInputManagerFuncs;
108
109    // The synchronization root for the display manager.
110    // This lock guards most of the display manager's state.
111    private final SyncRoot mSyncRoot = new SyncRoot();
112
113    // True if in safe mode.
114    // This option may disable certain display adapters.
115    public boolean mSafeMode;
116
117    // True if we are in a special boot mode where only core applications and
118    // services should be started.  This option may disable certain display adapters.
119    public boolean mOnlyCore;
120
121    // All callback records indexed by calling process id.
122    public final SparseArray<CallbackRecord> mCallbacks =
123            new SparseArray<CallbackRecord>();
124
125    // List of all currently registered display adapters.
126    private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
127
128    // List of all currently connected display devices.
129    private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>();
130
131    // List of all removed display devices.
132    private final ArrayList<DisplayDevice> mRemovedDisplayDevices = new ArrayList<DisplayDevice>();
133
134    // List of all logical displays indexed by logical display id.
135    private final SparseArray<LogicalDisplay> mLogicalDisplays =
136            new SparseArray<LogicalDisplay>();
137    private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
138
139    // Set to true when there are pending display changes that have yet to be applied
140    // to the surface flinger state.
141    private boolean mPendingTraversal;
142
143    // The Wifi display adapter, or null if not registered.
144    private WifiDisplayAdapter mWifiDisplayAdapter;
145
146    // Viewports of the default display and the display that should receive touch
147    // input from an external source.  Used by the input system.
148    private final DisplayViewport mDefaultViewport = new DisplayViewport();
149    private final DisplayViewport mExternalTouchViewport = new DisplayViewport();
150
151    // Persistent data store for all internal settings maintained by the display manager service.
152    private final PersistentDataStore mPersistentDataStore = new PersistentDataStore();
153
154    // Temporary callback list, used when sending display events to applications.
155    // May be used outside of the lock but only on the handler thread.
156    private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
157
158    // Temporary display info, used for comparing display configurations.
159    private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
160
161    // Temporary viewports, used when sending new viewport information to the
162    // input system.  May be used outside of the lock but only on the handler thread.
163    private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
164    private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
165
166    public DisplayManagerService(Context context, Handler mainHandler, Handler uiHandler) {
167        mContext = context;
168        mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
169
170        mHandler = new DisplayManagerHandler(mainHandler.getLooper());
171        mUiHandler = uiHandler;
172        mDisplayAdapterListener = new DisplayAdapterListener();
173
174        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
175    }
176
177    /**
178     * Pauses the boot process to wait for the first display to be initialized.
179     */
180    public boolean waitForDefaultDisplay() {
181        synchronized (mSyncRoot) {
182            long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
183            while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
184                long delay = timeout - SystemClock.uptimeMillis();
185                if (delay <= 0) {
186                    return false;
187                }
188                if (DEBUG) {
189                    Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
190                }
191                try {
192                    mSyncRoot.wait(delay);
193                } catch (InterruptedException ex) {
194                }
195            }
196        }
197        return true;
198    }
199
200    /**
201     * Called during initialization to associate the display manager with the
202     * window manager.
203     */
204    public void setWindowManager(WindowManagerFuncs windowManagerFuncs) {
205        synchronized (mSyncRoot) {
206            mWindowManagerFuncs = windowManagerFuncs;
207            scheduleTraversalLocked();
208        }
209    }
210
211    /**
212     * Called during initialization to associate the display manager with the
213     * input manager.
214     */
215    public void setInputManager(InputManagerFuncs inputManagerFuncs) {
216        synchronized (mSyncRoot) {
217            mInputManagerFuncs = inputManagerFuncs;
218            scheduleTraversalLocked();
219        }
220    }
221
222    /**
223     * Called when the system is ready to go.
224     */
225    public void systemReady(boolean safeMode, boolean onlyCore) {
226        synchronized (mSyncRoot) {
227            mSafeMode = safeMode;
228            mOnlyCore = onlyCore;
229        }
230
231        mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
232    }
233
234    /**
235     * Returns true if the device is headless.
236     *
237     * @return True if the device is headless.
238     */
239    public boolean isHeadless() {
240        return mHeadless;
241    }
242
243    /**
244     * Overrides the display information of a particular logical display.
245     * This is used by the window manager to control the size and characteristics
246     * of the default display.  It is expected to apply the requested change
247     * to the display information synchronously so that applications will immediately
248     * observe the new state.
249     *
250     * @param displayId The logical display id.
251     * @param info The new data to be stored.
252     */
253    public void setDisplayInfoOverrideFromWindowManager(
254            int displayId, DisplayInfo info) {
255        synchronized (mSyncRoot) {
256            LogicalDisplay display = mLogicalDisplays.get(displayId);
257            if (display != null) {
258                mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
259                display.setDisplayInfoOverrideFromWindowManagerLocked(info);
260                if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
261                    sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
262                    scheduleTraversalLocked();
263                }
264            }
265        }
266    }
267
268    /**
269     * Called by the window manager to perform traversals while holding a
270     * surface flinger transaction.
271     */
272    public void performTraversalInTransactionFromWindowManager() {
273        synchronized (mSyncRoot) {
274            if (!mPendingTraversal) {
275                return;
276            }
277            mPendingTraversal = false;
278
279            performTraversalInTransactionLocked();
280        }
281    }
282
283    /**
284     * Returns information about the specified logical display.
285     *
286     * @param displayId The logical display id.
287     * @return The logical display info, or null if the display does not exist.  The
288     * returned object must be treated as immutable.
289     */
290    @Override // Binder call
291    public DisplayInfo getDisplayInfo(int displayId) {
292        synchronized (mSyncRoot) {
293            LogicalDisplay display = mLogicalDisplays.get(displayId);
294            if (display != null) {
295                return display.getDisplayInfoLocked();
296            }
297            return null;
298        }
299    }
300
301    /**
302     * Returns the list of all display ids.
303     */
304    @Override // Binder call
305    public int[] getDisplayIds() {
306        synchronized (mSyncRoot) {
307            final int count = mLogicalDisplays.size();
308            int[] displayIds = new int[count];
309            for (int i = 0; i < count; i++) {
310                displayIds[i] = mLogicalDisplays.keyAt(i);
311            }
312            return displayIds;
313        }
314    }
315
316    @Override // Binder call
317    public void registerCallback(IDisplayManagerCallback callback) {
318        if (callback == null) {
319            throw new IllegalArgumentException("listener must not be null");
320        }
321
322        synchronized (mSyncRoot) {
323            int callingPid = Binder.getCallingPid();
324            if (mCallbacks.get(callingPid) != null) {
325                throw new SecurityException("The calling process has already "
326                        + "registered an IDisplayManagerCallback.");
327            }
328
329            CallbackRecord record = new CallbackRecord(callingPid, callback);
330            try {
331                IBinder binder = callback.asBinder();
332                binder.linkToDeath(record, 0);
333            } catch (RemoteException ex) {
334                // give up
335                throw new RuntimeException(ex);
336            }
337
338            mCallbacks.put(callingPid, record);
339        }
340    }
341
342    private void onCallbackDied(int pid) {
343        synchronized (mSyncRoot) {
344            mCallbacks.remove(pid);
345        }
346    }
347
348    @Override // Binder call
349    public void scanWifiDisplays() {
350        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
351                != PackageManager.PERMISSION_GRANTED) {
352            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
353        }
354
355        final long token = Binder.clearCallingIdentity();
356        try {
357            synchronized (mSyncRoot) {
358                if (mWifiDisplayAdapter != null) {
359                    mWifiDisplayAdapter.requestScanLocked();
360                }
361            }
362        } finally {
363            Binder.restoreCallingIdentity(token);
364        }
365    }
366
367    @Override // Binder call
368    public void connectWifiDisplay(String address) {
369        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
370                != PackageManager.PERMISSION_GRANTED) {
371            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
372        }
373        if (address == null) {
374            throw new IllegalArgumentException("address must not be null");
375        }
376
377        final long token = Binder.clearCallingIdentity();
378        try {
379            synchronized (mSyncRoot) {
380                if (mWifiDisplayAdapter != null) {
381                    mWifiDisplayAdapter.requestConnectLocked(address);
382                }
383            }
384        } finally {
385            Binder.restoreCallingIdentity(token);
386        }
387    }
388
389    @Override // Binder call
390    public void disconnectWifiDisplay() {
391        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
392                != PackageManager.PERMISSION_GRANTED) {
393            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
394        }
395
396        final long token = Binder.clearCallingIdentity();
397        try {
398            synchronized (mSyncRoot) {
399                if (mWifiDisplayAdapter != null) {
400                    mWifiDisplayAdapter.requestDisconnectLocked();
401                }
402            }
403        } finally {
404            Binder.restoreCallingIdentity(token);
405        }
406    }
407
408    @Override // Binder call
409    public void renameWifiDisplay(String address, String alias) {
410        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
411                != PackageManager.PERMISSION_GRANTED) {
412            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
413        }
414        if (address == null) {
415            throw new IllegalArgumentException("address must not be null");
416        }
417
418        final long token = Binder.clearCallingIdentity();
419        try {
420            synchronized (mSyncRoot) {
421                if (mWifiDisplayAdapter != null) {
422                    mWifiDisplayAdapter.requestRenameLocked(address, alias);
423                }
424            }
425        } finally {
426            Binder.restoreCallingIdentity(token);
427        }
428    }
429
430    @Override // Binder call
431    public void forgetWifiDisplay(String address) {
432        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
433                != PackageManager.PERMISSION_GRANTED) {
434            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
435        }
436        if (address == null) {
437            throw new IllegalArgumentException("address must not be null");
438        }
439
440        final long token = Binder.clearCallingIdentity();
441        try {
442            synchronized (mSyncRoot) {
443                if (mWifiDisplayAdapter != null) {
444                    mWifiDisplayAdapter.requestForgetLocked(address);
445                }
446            }
447        } finally {
448            Binder.restoreCallingIdentity(token);
449        }
450    }
451
452    @Override // Binder call
453    public WifiDisplayStatus getWifiDisplayStatus() {
454        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
455                != PackageManager.PERMISSION_GRANTED) {
456            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
457        }
458
459        final long token = Binder.clearCallingIdentity();
460        try {
461            synchronized (mSyncRoot) {
462                if (mWifiDisplayAdapter != null) {
463                    return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
464                } else {
465                    return new WifiDisplayStatus();
466                }
467            }
468        } finally {
469            Binder.restoreCallingIdentity(token);
470        }
471    }
472
473    private void registerDefaultDisplayAdapter() {
474        // Register default display adapter.
475        synchronized (mSyncRoot) {
476            if (mHeadless) {
477                registerDisplayAdapterLocked(new HeadlessDisplayAdapter(
478                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
479            } else {
480                registerDisplayAdapterLocked(new LocalDisplayAdapter(
481                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
482            }
483        }
484    }
485
486    private void registerAdditionalDisplayAdapters() {
487        synchronized (mSyncRoot) {
488            if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
489                registerOverlayDisplayAdapterLocked();
490                registerWifiDisplayAdapterLocked();
491            }
492        }
493    }
494
495    private void registerOverlayDisplayAdapterLocked() {
496        registerDisplayAdapterLocked(new OverlayDisplayAdapter(
497                mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
498    }
499
500    private void registerWifiDisplayAdapterLocked() {
501        if (mContext.getResources().getBoolean(
502                com.android.internal.R.bool.config_enableWifiDisplay)) {
503            mWifiDisplayAdapter = new WifiDisplayAdapter(
504                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener,
505                    mPersistentDataStore);
506            registerDisplayAdapterLocked(mWifiDisplayAdapter);
507        }
508    }
509
510    private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
511        // In safe mode, we disable non-essential display adapters to give the user
512        // an opportunity to fix broken settings or other problems that might affect
513        // system stability.
514        // In only-core mode, we disable non-essential display adapters to minimize
515        // the number of dependencies that are started while in this mode and to
516        // prevent problems that might occur due to the device being encrypted.
517        return !mSafeMode && !mOnlyCore;
518    }
519
520    private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
521        mDisplayAdapters.add(adapter);
522        adapter.registerLocked();
523    }
524
525    private void handleDisplayDeviceAdded(DisplayDevice device) {
526        synchronized (mSyncRoot) {
527            if (mDisplayDevices.contains(device)) {
528                Slog.w(TAG, "Attempted to add already added display device: "
529                        + device.getDisplayDeviceInfoLocked());
530                return;
531            }
532
533            mDisplayDevices.add(device);
534            addLogicalDisplayLocked(device);
535            scheduleTraversalLocked();
536        }
537    }
538
539    private void handleDisplayDeviceChanged(DisplayDevice device) {
540        synchronized (mSyncRoot) {
541            if (!mDisplayDevices.contains(device)) {
542                Slog.w(TAG, "Attempted to change non-existent display device: "
543                        + device.getDisplayDeviceInfoLocked());
544                return;
545            }
546
547            device.applyPendingDisplayDeviceInfoChangesLocked();
548            if (updateLogicalDisplaysLocked()) {
549                scheduleTraversalLocked();
550            }
551        }
552    }
553
554    private void handleDisplayDeviceRemoved(DisplayDevice device) {
555        synchronized (mSyncRoot) {
556            if (!mDisplayDevices.remove(device)) {
557                Slog.w(TAG, "Attempted to remove non-existent display device: "
558                        + device.getDisplayDeviceInfoLocked());
559                return;
560            }
561
562            mRemovedDisplayDevices.add(device);
563            updateLogicalDisplaysLocked();
564            scheduleTraversalLocked();
565        }
566    }
567
568    // Adds a new logical display based on the given display device.
569    // Sends notifications if needed.
570    private void addLogicalDisplayLocked(DisplayDevice device) {
571        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
572        boolean isDefault = (deviceInfo.flags
573                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
574        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
575            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
576            isDefault = false;
577        }
578
579        final int displayId = assignDisplayIdLocked(isDefault);
580        final int layerStack = assignLayerStackLocked(displayId);
581
582        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
583        display.updateLocked(mDisplayDevices);
584        if (!display.isValidLocked()) {
585            // This should never happen currently.
586            Slog.w(TAG, "Ignoring display device because the logical display "
587                    + "created from it was not considered valid: " + deviceInfo);
588            return;
589        }
590
591        mLogicalDisplays.put(displayId, display);
592
593        // Wake up waitForDefaultDisplay.
594        if (isDefault) {
595            mSyncRoot.notifyAll();
596        }
597
598        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
599    }
600
601    private int assignDisplayIdLocked(boolean isDefault) {
602        return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
603    }
604
605    private int assignLayerStackLocked(int displayId) {
606        // Currently layer stacks and display ids are the same.
607        // This need not be the case.
608        return displayId;
609    }
610
611    // Updates all existing logical displays given the current set of display devices.
612    // Removes invalid logical displays.
613    // Sends notifications if needed.
614    private boolean updateLogicalDisplaysLocked() {
615        boolean changed = false;
616        for (int i = mLogicalDisplays.size(); i-- > 0; ) {
617            final int displayId = mLogicalDisplays.keyAt(i);
618            LogicalDisplay display = mLogicalDisplays.valueAt(i);
619
620            mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
621            display.updateLocked(mDisplayDevices);
622            if (!display.isValidLocked()) {
623                mLogicalDisplays.removeAt(i);
624                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
625                changed = true;
626            } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
627                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
628                changed = true;
629            }
630        }
631        return changed;
632    }
633
634    private void performTraversalInTransactionLocked() {
635        // Perform one last traversal for each removed display device.
636        final int removedCount = mRemovedDisplayDevices.size();
637        for (int i = 0; i < removedCount; i++) {
638            DisplayDevice device = mRemovedDisplayDevices.get(i);
639            device.performTraversalInTransactionLocked();
640        }
641        mRemovedDisplayDevices.clear();
642
643        // Clear all viewports before configuring displays so that we can keep
644        // track of which ones we have configured.
645        clearViewportsLocked();
646
647        // Configure each display device.
648        final int count = mDisplayDevices.size();
649        for (int i = 0; i < count; i++) {
650            DisplayDevice device = mDisplayDevices.get(i);
651            configureDisplayInTransactionLocked(device);
652            device.performTraversalInTransactionLocked();
653        }
654
655        // Tell the input system about these new viewports.
656        if (mInputManagerFuncs != null) {
657            mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
658        }
659    }
660
661    /**
662     * Tells the display manager whether there is interesting unique content on the
663     * specified logical display.  This is used to control automatic mirroring.
664     * <p>
665     * If the display has unique content, then the display manager arranges for it
666     * to be presented on a physical display if appropriate.  Otherwise, the display manager
667     * may choose to make the physical display mirror some other logical display.
668     * </p>
669     *
670     * @param displayId The logical display id to update.
671     * @param hasContent True if the logical display has content.
672     */
673    public void setDisplayHasContent(int displayId, boolean hasContent) {
674        synchronized (mSyncRoot) {
675            LogicalDisplay display = mLogicalDisplays.get(displayId);
676            if (display != null && display.hasContentLocked() != hasContent) {
677                display.setHasContentLocked(hasContent);
678                scheduleTraversalLocked();
679            }
680        }
681    }
682
683    private void clearViewportsLocked() {
684        mDefaultViewport.valid = false;
685        mExternalTouchViewport.valid = false;
686    }
687
688    private void configureDisplayInTransactionLocked(DisplayDevice device) {
689        // Find the logical display that the display device is showing.
690        LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
691        if (display != null && !display.hasContentLocked()) {
692            display = null;
693        }
694        if (display == null) {
695            display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
696        }
697
698        // Apply the logical display configuration to the display device.
699        if (display == null) {
700            // TODO: no logical display for the device, blank it
701            Slog.w(TAG, "Missing logical display to use for physical display device: "
702                    + device.getDisplayDeviceInfoLocked());
703            return;
704        } else {
705            display.configureDisplayInTransactionLocked(device);
706        }
707
708        // Update the viewports if needed.
709        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
710        if (!mDefaultViewport.valid
711                && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
712            setViewportLocked(mDefaultViewport, display, device);
713        }
714        if (!mExternalTouchViewport.valid
715                && info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
716            setViewportLocked(mExternalTouchViewport, display, device);
717        }
718    }
719
720    private static void setViewportLocked(DisplayViewport viewport,
721            LogicalDisplay display, DisplayDevice device) {
722        viewport.valid = true;
723        viewport.displayId = display.getDisplayIdLocked();
724        device.populateViewportLocked(viewport);
725    }
726
727    private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) {
728        final int count = mLogicalDisplays.size();
729        for (int i = 0; i < count; i++) {
730            LogicalDisplay display = mLogicalDisplays.valueAt(i);
731            if (display.getPrimaryDisplayDeviceLocked() == device) {
732                return display;
733            }
734        }
735        return null;
736    }
737
738    private void sendDisplayEventLocked(int displayId, int event) {
739        Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
740        mHandler.sendMessage(msg);
741    }
742
743    // Requests that performTraversalsInTransactionFromWindowManager be called at a
744    // later time to apply changes to surfaces and displays.
745    private void scheduleTraversalLocked() {
746        if (!mPendingTraversal && mWindowManagerFuncs != null) {
747            mPendingTraversal = true;
748            mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
749        }
750    }
751
752    // Runs on Handler thread.
753    // Delivers display event notifications to callbacks.
754    private void deliverDisplayEvent(int displayId, int event) {
755        if (DEBUG) {
756            Slog.d(TAG, "Delivering display event: displayId="
757                    + displayId + ", event=" + event);
758        }
759
760        // Grab the lock and copy the callbacks.
761        final int count;
762        synchronized (mSyncRoot) {
763            count = mCallbacks.size();
764            mTempCallbacks.clear();
765            for (int i = 0; i < count; i++) {
766                mTempCallbacks.add(mCallbacks.valueAt(i));
767            }
768        }
769
770        // After releasing the lock, send the notifications out.
771        for (int i = 0; i < count; i++) {
772            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
773        }
774        mTempCallbacks.clear();
775    }
776
777    @Override // Binder call
778    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
779        if (mContext == null
780                || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
781                        != PackageManager.PERMISSION_GRANTED) {
782            pw.println("Permission Denial: can't dump DisplayManager from from pid="
783                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
784            return;
785        }
786
787        pw.println("DISPLAY MANAGER (dumpsys display)");
788        pw.println("  mHeadless=" + mHeadless);
789
790        synchronized (mSyncRoot) {
791            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
792            ipw.increaseIndent();
793
794            pw.println();
795            pw.println("Display Adapters: size=" + mDisplayAdapters.size());
796            for (DisplayAdapter adapter : mDisplayAdapters) {
797                pw.println("  " + adapter.getName());
798                adapter.dumpLocked(ipw);
799            }
800
801            pw.println();
802            pw.println("Display Devices: size=" + mDisplayDevices.size());
803            for (DisplayDevice device : mDisplayDevices) {
804                pw.println("  " + device.getDisplayDeviceInfoLocked());
805                device.dumpLocked(ipw);
806            }
807
808            final int logicalDisplayCount = mLogicalDisplays.size();
809            pw.println();
810            pw.println("Logical Displays: size=" + logicalDisplayCount);
811            for (int i = 0; i < logicalDisplayCount; i++) {
812                int displayId = mLogicalDisplays.keyAt(i);
813                LogicalDisplay display = mLogicalDisplays.valueAt(i);
814                pw.println("  Display " + displayId + ":");
815                display.dumpLocked(ipw);
816            }
817
818            pw.println();
819            pw.println("Default viewport: " + mDefaultViewport);
820            pw.println("External touch viewport: " + mExternalTouchViewport);
821        }
822    }
823
824    /**
825     * This is the object that everything in the display manager locks on.
826     * We make it an inner class within the {@link DisplayManagerService} to so that it is
827     * clear that the object belongs to the display manager service and that it is
828     * a unique object with a special purpose.
829     */
830    public static final class SyncRoot {
831    }
832
833    /**
834     * Private interface to the window manager.
835     */
836    public interface WindowManagerFuncs {
837        /**
838         * Request that the window manager call
839         * {@link #performTraversalInTransactionFromWindowManager} within a surface
840         * transaction at a later time.
841         */
842        void requestTraversal();
843    }
844
845    /**
846     * Private interface to the input manager.
847     */
848    public interface InputManagerFuncs {
849        /**
850         * Sets information about the displays as needed by the input system.
851         * The input system should copy this information if required.
852         */
853        void setDisplayViewports(DisplayViewport defaultViewport,
854                DisplayViewport externalTouchViewport);
855    }
856
857    private final class DisplayManagerHandler extends Handler {
858        public DisplayManagerHandler(Looper looper) {
859            super(looper, null, true /*async*/);
860        }
861
862        @Override
863        public void handleMessage(Message msg) {
864            switch (msg.what) {
865                case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
866                    registerDefaultDisplayAdapter();
867                    break;
868
869                case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
870                    registerAdditionalDisplayAdapters();
871                    break;
872
873                case MSG_DELIVER_DISPLAY_EVENT:
874                    deliverDisplayEvent(msg.arg1, msg.arg2);
875                    break;
876
877                case MSG_REQUEST_TRAVERSAL:
878                    mWindowManagerFuncs.requestTraversal();
879                    break;
880
881                case MSG_UPDATE_VIEWPORT: {
882                    synchronized (mSyncRoot) {
883                        mTempDefaultViewport.copyFrom(mDefaultViewport);
884                        mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
885                    }
886                    mInputManagerFuncs.setDisplayViewports(
887                            mTempDefaultViewport, mTempExternalTouchViewport);
888                    break;
889                }
890            }
891        }
892    }
893
894    private final class DisplayAdapterListener implements DisplayAdapter.Listener {
895        @Override
896        public void onDisplayDeviceEvent(DisplayDevice device, int event) {
897            switch (event) {
898                case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
899                    handleDisplayDeviceAdded(device);
900                    break;
901
902                case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
903                    handleDisplayDeviceChanged(device);
904                    break;
905
906                case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
907                    handleDisplayDeviceRemoved(device);
908                    break;
909            }
910        }
911
912        @Override
913        public void onTraversalRequested() {
914            synchronized (mSyncRoot) {
915                scheduleTraversalLocked();
916            }
917        }
918    }
919
920    private final class CallbackRecord implements DeathRecipient {
921        private final int mPid;
922        private final IDisplayManagerCallback mCallback;
923
924        public CallbackRecord(int pid, IDisplayManagerCallback callback) {
925            mPid = pid;
926            mCallback = callback;
927        }
928
929        @Override
930        public void binderDied() {
931            if (DEBUG) {
932                Slog.d(TAG, "Display listener for pid " + mPid + " died.");
933            }
934            onCallbackDied(mPid);
935        }
936
937        public void notifyDisplayEventAsync(int displayId, int event) {
938            try {
939                mCallback.onDisplayEvent(displayId, event);
940            } catch (RemoteException ex) {
941                Slog.w(TAG, "Failed to notify process "
942                        + mPid + " that displays changed, assuming it died.", ex);
943                binderDied();
944            }
945        }
946    }
947}
948