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