DisplayManagerService.java revision bbd28a293f84baeafed469c5e223eff82c1117c0
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();
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();
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();
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        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
356                != PackageManager.PERMISSION_GRANTED) {
357            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
358        }
359
360        final long token = Binder.clearCallingIdentity();
361        try {
362            synchronized (mSyncRoot) {
363                if (mWifiDisplayAdapter != null) {
364                    mWifiDisplayAdapter.requestScanLocked();
365                }
366            }
367        } finally {
368            Binder.restoreCallingIdentity(token);
369        }
370    }
371
372    @Override // Binder call
373    public void connectWifiDisplay(String address) {
374        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
375                != PackageManager.PERMISSION_GRANTED) {
376            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
377        }
378        if (address == null) {
379            throw new IllegalArgumentException("address must not be null");
380        }
381
382        final long token = Binder.clearCallingIdentity();
383        try {
384            synchronized (mSyncRoot) {
385                if (mWifiDisplayAdapter != null) {
386                    mWifiDisplayAdapter.requestConnectLocked(address);
387                }
388            }
389        } finally {
390            Binder.restoreCallingIdentity(token);
391        }
392    }
393
394    @Override // Binder call
395    public void disconnectWifiDisplay() {
396        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
397                != PackageManager.PERMISSION_GRANTED) {
398            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
399        }
400
401        final long token = Binder.clearCallingIdentity();
402        try {
403            synchronized (mSyncRoot) {
404                if (mWifiDisplayAdapter != null) {
405                    mWifiDisplayAdapter.requestDisconnectLocked();
406                }
407            }
408        } finally {
409            Binder.restoreCallingIdentity(token);
410        }
411    }
412
413    @Override // Binder call
414    public void renameWifiDisplay(String address, String alias) {
415        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
416                != PackageManager.PERMISSION_GRANTED) {
417            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
418        }
419        if (address == null) {
420            throw new IllegalArgumentException("address must not be null");
421        }
422
423        final long token = Binder.clearCallingIdentity();
424        try {
425            synchronized (mSyncRoot) {
426                if (mWifiDisplayAdapter != null) {
427                    mWifiDisplayAdapter.requestRenameLocked(address, alias);
428                }
429            }
430        } finally {
431            Binder.restoreCallingIdentity(token);
432        }
433    }
434
435    @Override // Binder call
436    public void forgetWifiDisplay(String address) {
437        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
438                != PackageManager.PERMISSION_GRANTED) {
439            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
440        }
441        if (address == null) {
442            throw new IllegalArgumentException("address must not be null");
443        }
444
445        final long token = Binder.clearCallingIdentity();
446        try {
447            synchronized (mSyncRoot) {
448                if (mWifiDisplayAdapter != null) {
449                    mWifiDisplayAdapter.requestForgetLocked(address);
450                }
451            }
452        } finally {
453            Binder.restoreCallingIdentity(token);
454        }
455    }
456
457    @Override // Binder call
458    public WifiDisplayStatus getWifiDisplayStatus() {
459        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
460                != PackageManager.PERMISSION_GRANTED) {
461            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
462        }
463
464        final long token = Binder.clearCallingIdentity();
465        try {
466            synchronized (mSyncRoot) {
467                if (mWifiDisplayAdapter != null) {
468                    return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
469                } else {
470                    return new WifiDisplayStatus();
471                }
472            }
473        } finally {
474            Binder.restoreCallingIdentity(token);
475        }
476    }
477
478    private void registerDefaultDisplayAdapter() {
479        // Register default display adapter.
480        synchronized (mSyncRoot) {
481            if (mHeadless) {
482                registerDisplayAdapterLocked(new HeadlessDisplayAdapter(
483                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
484            } else {
485                registerDisplayAdapterLocked(new LocalDisplayAdapter(
486                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
487            }
488        }
489    }
490
491    private void registerAdditionalDisplayAdapters() {
492        synchronized (mSyncRoot) {
493            if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
494                registerOverlayDisplayAdapterLocked();
495                registerWifiDisplayAdapterLocked();
496            }
497        }
498    }
499
500    private void registerOverlayDisplayAdapterLocked() {
501        registerDisplayAdapterLocked(new OverlayDisplayAdapter(
502                mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
503    }
504
505    private void registerWifiDisplayAdapterLocked() {
506        if (mContext.getResources().getBoolean(
507                com.android.internal.R.bool.config_enableWifiDisplay)
508                || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) {
509            mWifiDisplayAdapter = new WifiDisplayAdapter(
510                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener,
511                    mPersistentDataStore);
512            registerDisplayAdapterLocked(mWifiDisplayAdapter);
513        }
514    }
515
516    private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
517        // In safe mode, we disable non-essential display adapters to give the user
518        // an opportunity to fix broken settings or other problems that might affect
519        // system stability.
520        // In only-core mode, we disable non-essential display adapters to minimize
521        // the number of dependencies that are started while in this mode and to
522        // prevent problems that might occur due to the device being encrypted.
523        return !mSafeMode && !mOnlyCore;
524    }
525
526    private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
527        mDisplayAdapters.add(adapter);
528        adapter.registerLocked();
529    }
530
531    private void handleDisplayDeviceAdded(DisplayDevice device) {
532        synchronized (mSyncRoot) {
533            if (mDisplayDevices.contains(device)) {
534                Slog.w(TAG, "Attempted to add already added display device: "
535                        + device.getDisplayDeviceInfoLocked());
536                return;
537            }
538
539            mDisplayDevices.add(device);
540            addLogicalDisplayLocked(device);
541            scheduleTraversalLocked();
542        }
543    }
544
545    private void handleDisplayDeviceChanged(DisplayDevice device) {
546        synchronized (mSyncRoot) {
547            if (!mDisplayDevices.contains(device)) {
548                Slog.w(TAG, "Attempted to change non-existent display device: "
549                        + device.getDisplayDeviceInfoLocked());
550                return;
551            }
552
553            device.applyPendingDisplayDeviceInfoChangesLocked();
554            if (updateLogicalDisplaysLocked()) {
555                scheduleTraversalLocked();
556            }
557        }
558    }
559
560    private void handleDisplayDeviceRemoved(DisplayDevice device) {
561        synchronized (mSyncRoot) {
562            if (!mDisplayDevices.remove(device)) {
563                Slog.w(TAG, "Attempted to remove non-existent display device: "
564                        + device.getDisplayDeviceInfoLocked());
565                return;
566            }
567
568            mRemovedDisplayDevices.add(device);
569            updateLogicalDisplaysLocked();
570            scheduleTraversalLocked();
571        }
572    }
573
574    // Adds a new logical display based on the given display device.
575    // Sends notifications if needed.
576    private void addLogicalDisplayLocked(DisplayDevice device) {
577        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
578        boolean isDefault = (deviceInfo.flags
579                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
580        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
581            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
582            isDefault = false;
583        }
584
585        final int displayId = assignDisplayIdLocked(isDefault);
586        final int layerStack = assignLayerStackLocked(displayId);
587
588        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
589        display.updateLocked(mDisplayDevices);
590        if (!display.isValidLocked()) {
591            // This should never happen currently.
592            Slog.w(TAG, "Ignoring display device because the logical display "
593                    + "created from it was not considered valid: " + deviceInfo);
594            return;
595        }
596
597        mLogicalDisplays.put(displayId, display);
598
599        // Wake up waitForDefaultDisplay.
600        if (isDefault) {
601            mSyncRoot.notifyAll();
602        }
603
604        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
605    }
606
607    private int assignDisplayIdLocked(boolean isDefault) {
608        return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
609    }
610
611    private int assignLayerStackLocked(int displayId) {
612        // Currently layer stacks and display ids are the same.
613        // This need not be the case.
614        return displayId;
615    }
616
617    // Updates all existing logical displays given the current set of display devices.
618    // Removes invalid logical displays.
619    // Sends notifications if needed.
620    private boolean updateLogicalDisplaysLocked() {
621        boolean changed = false;
622        for (int i = mLogicalDisplays.size(); i-- > 0; ) {
623            final int displayId = mLogicalDisplays.keyAt(i);
624            LogicalDisplay display = mLogicalDisplays.valueAt(i);
625
626            mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
627            display.updateLocked(mDisplayDevices);
628            if (!display.isValidLocked()) {
629                mLogicalDisplays.removeAt(i);
630                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
631                changed = true;
632            } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
633                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
634                changed = true;
635            }
636        }
637        return changed;
638    }
639
640    private void performTraversalInTransactionLocked() {
641        // Perform one last traversal for each removed display device.
642        final int removedCount = mRemovedDisplayDevices.size();
643        for (int i = 0; i < removedCount; i++) {
644            DisplayDevice device = mRemovedDisplayDevices.get(i);
645            device.performTraversalInTransactionLocked();
646        }
647        mRemovedDisplayDevices.clear();
648
649        // Clear all viewports before configuring displays so that we can keep
650        // track of which ones we have configured.
651        clearViewportsLocked();
652
653        // Configure each display device.
654        final int count = mDisplayDevices.size();
655        for (int i = 0; i < count; i++) {
656            DisplayDevice device = mDisplayDevices.get(i);
657            configureDisplayInTransactionLocked(device);
658            device.performTraversalInTransactionLocked();
659        }
660
661        // Tell the input system about these new viewports.
662        if (mInputManagerFuncs != null) {
663            mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
664        }
665    }
666
667    /**
668     * Tells the display manager whether there is interesting unique content on the
669     * specified logical display.  This is used to control automatic mirroring.
670     * <p>
671     * If the display has unique content, then the display manager arranges for it
672     * to be presented on a physical display if appropriate.  Otherwise, the display manager
673     * may choose to make the physical display mirror some other logical display.
674     * </p>
675     *
676     * @param displayId The logical display id to update.
677     * @param hasContent True if the logical display has content.
678     */
679    public void setDisplayHasContent(int displayId, boolean hasContent) {
680        synchronized (mSyncRoot) {
681            LogicalDisplay display = mLogicalDisplays.get(displayId);
682            if (display != null && display.hasContentLocked() != hasContent) {
683                display.setHasContentLocked(hasContent);
684                scheduleTraversalLocked();
685            }
686        }
687    }
688
689    private void clearViewportsLocked() {
690        mDefaultViewport.valid = false;
691        mExternalTouchViewport.valid = false;
692    }
693
694    private void configureDisplayInTransactionLocked(DisplayDevice device) {
695        // Find the logical display that the display device is showing.
696        LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
697        if (display != null && !display.hasContentLocked()) {
698            display = null;
699        }
700        if (display == null) {
701            display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
702        }
703
704        // Apply the logical display configuration to the display device.
705        if (display == null) {
706            // TODO: no logical display for the device, blank it
707            Slog.w(TAG, "Missing logical display to use for physical display device: "
708                    + device.getDisplayDeviceInfoLocked());
709            return;
710        } else {
711            display.configureDisplayInTransactionLocked(device);
712        }
713
714        // Update the viewports if needed.
715        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
716        if (!mDefaultViewport.valid
717                && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
718            setViewportLocked(mDefaultViewport, display, device);
719        }
720        if (!mExternalTouchViewport.valid
721                && info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
722            setViewportLocked(mExternalTouchViewport, display, device);
723        }
724    }
725
726    private static void setViewportLocked(DisplayViewport viewport,
727            LogicalDisplay display, DisplayDevice device) {
728        viewport.valid = true;
729        viewport.displayId = display.getDisplayIdLocked();
730        device.populateViewportLocked(viewport);
731    }
732
733    private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) {
734        final int count = mLogicalDisplays.size();
735        for (int i = 0; i < count; i++) {
736            LogicalDisplay display = mLogicalDisplays.valueAt(i);
737            if (display.getPrimaryDisplayDeviceLocked() == device) {
738                return display;
739            }
740        }
741        return null;
742    }
743
744    private void sendDisplayEventLocked(int displayId, int event) {
745        Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
746        mHandler.sendMessage(msg);
747    }
748
749    // Requests that performTraversalsInTransactionFromWindowManager be called at a
750    // later time to apply changes to surfaces and displays.
751    private void scheduleTraversalLocked() {
752        if (!mPendingTraversal && mWindowManagerFuncs != null) {
753            mPendingTraversal = true;
754            mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
755        }
756    }
757
758    // Runs on Handler thread.
759    // Delivers display event notifications to callbacks.
760    private void deliverDisplayEvent(int displayId, int event) {
761        if (DEBUG) {
762            Slog.d(TAG, "Delivering display event: displayId="
763                    + displayId + ", event=" + event);
764        }
765
766        // Grab the lock and copy the callbacks.
767        final int count;
768        synchronized (mSyncRoot) {
769            count = mCallbacks.size();
770            mTempCallbacks.clear();
771            for (int i = 0; i < count; i++) {
772                mTempCallbacks.add(mCallbacks.valueAt(i));
773            }
774        }
775
776        // After releasing the lock, send the notifications out.
777        for (int i = 0; i < count; i++) {
778            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
779        }
780        mTempCallbacks.clear();
781    }
782
783    @Override // Binder call
784    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
785        if (mContext == null
786                || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
787                        != PackageManager.PERMISSION_GRANTED) {
788            pw.println("Permission Denial: can't dump DisplayManager from from pid="
789                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
790            return;
791        }
792
793        pw.println("DISPLAY MANAGER (dumpsys display)");
794        pw.println("  mHeadless=" + mHeadless);
795
796        synchronized (mSyncRoot) {
797            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
798            ipw.increaseIndent();
799
800            pw.println();
801            pw.println("Display Adapters: size=" + mDisplayAdapters.size());
802            for (DisplayAdapter adapter : mDisplayAdapters) {
803                pw.println("  " + adapter.getName());
804                adapter.dumpLocked(ipw);
805            }
806
807            pw.println();
808            pw.println("Display Devices: size=" + mDisplayDevices.size());
809            for (DisplayDevice device : mDisplayDevices) {
810                pw.println("  " + device.getDisplayDeviceInfoLocked());
811                device.dumpLocked(ipw);
812            }
813
814            final int logicalDisplayCount = mLogicalDisplays.size();
815            pw.println();
816            pw.println("Logical Displays: size=" + logicalDisplayCount);
817            for (int i = 0; i < logicalDisplayCount; i++) {
818                int displayId = mLogicalDisplays.keyAt(i);
819                LogicalDisplay display = mLogicalDisplays.valueAt(i);
820                pw.println("  Display " + displayId + ":");
821                display.dumpLocked(ipw);
822            }
823
824            pw.println();
825            pw.println("Default viewport: " + mDefaultViewport);
826            pw.println("External touch viewport: " + mExternalTouchViewport);
827        }
828    }
829
830    /**
831     * This is the object that everything in the display manager locks on.
832     * We make it an inner class within the {@link DisplayManagerService} to so that it is
833     * clear that the object belongs to the display manager service and that it is
834     * a unique object with a special purpose.
835     */
836    public static final class SyncRoot {
837    }
838
839    /**
840     * Private interface to the window manager.
841     */
842    public interface WindowManagerFuncs {
843        /**
844         * Request that the window manager call
845         * {@link #performTraversalInTransactionFromWindowManager} within a surface
846         * transaction at a later time.
847         */
848        void requestTraversal();
849    }
850
851    /**
852     * Private interface to the input manager.
853     */
854    public interface InputManagerFuncs {
855        /**
856         * Sets information about the displays as needed by the input system.
857         * The input system should copy this information if required.
858         */
859        void setDisplayViewports(DisplayViewport defaultViewport,
860                DisplayViewport externalTouchViewport);
861    }
862
863    private final class DisplayManagerHandler extends Handler {
864        public DisplayManagerHandler(Looper looper) {
865            super(looper, null, true /*async*/);
866        }
867
868        @Override
869        public void handleMessage(Message msg) {
870            switch (msg.what) {
871                case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
872                    registerDefaultDisplayAdapter();
873                    break;
874
875                case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
876                    registerAdditionalDisplayAdapters();
877                    break;
878
879                case MSG_DELIVER_DISPLAY_EVENT:
880                    deliverDisplayEvent(msg.arg1, msg.arg2);
881                    break;
882
883                case MSG_REQUEST_TRAVERSAL:
884                    mWindowManagerFuncs.requestTraversal();
885                    break;
886
887                case MSG_UPDATE_VIEWPORT: {
888                    synchronized (mSyncRoot) {
889                        mTempDefaultViewport.copyFrom(mDefaultViewport);
890                        mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
891                    }
892                    mInputManagerFuncs.setDisplayViewports(
893                            mTempDefaultViewport, mTempExternalTouchViewport);
894                    break;
895                }
896            }
897        }
898    }
899
900    private final class DisplayAdapterListener implements DisplayAdapter.Listener {
901        @Override
902        public void onDisplayDeviceEvent(DisplayDevice device, int event) {
903            switch (event) {
904                case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
905                    handleDisplayDeviceAdded(device);
906                    break;
907
908                case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
909                    handleDisplayDeviceChanged(device);
910                    break;
911
912                case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
913                    handleDisplayDeviceRemoved(device);
914                    break;
915            }
916        }
917
918        @Override
919        public void onTraversalRequested() {
920            synchronized (mSyncRoot) {
921                scheduleTraversalLocked();
922            }
923        }
924    }
925
926    private final class CallbackRecord implements DeathRecipient {
927        private final int mPid;
928        private final IDisplayManagerCallback mCallback;
929
930        public CallbackRecord(int pid, IDisplayManagerCallback callback) {
931            mPid = pid;
932            mCallback = callback;
933        }
934
935        @Override
936        public void binderDied() {
937            if (DEBUG) {
938                Slog.d(TAG, "Display listener for pid " + mPid + " died.");
939            }
940            onCallbackDied(mPid);
941        }
942
943        public void notifyDisplayEventAsync(int displayId, int event) {
944            try {
945                mCallback.onDisplayEvent(displayId, event);
946            } catch (RemoteException ex) {
947                Slog.w(TAG, "Failed to notify process "
948                        + mPid + " that displays changed, assuming it died.", ex);
949                binderDied();
950            }
951        }
952    }
953}
954