FileDocCategorySizeDatePackage
DisplayManagerService.javaAPI DocAndroid 5.1 API60953Thu Mar 12 22:22:42 GMT 2015com.android.server.display

DisplayManagerService

public final class DisplayManagerService extends com.android.server.SystemService
Manages attached displays.

The {@link DisplayManagerService} manages the global lifecycle of displays, decides how to configure logical displays based on the physical display devices currently attached, sends notifications to the system and to applications when the state changes, and so on.

The display manager service relies on a collection of {@link DisplayAdapter} components, for discovering and configuring physical display devices attached to the system. There are separate display adapters for each manner that devices are attached: one display adapter for built-in local displays, one for simulated non-functional displays when the system is headless, one for simulated overlay displays used for development, one for wifi displays, etc.

Display adapters are only weakly coupled to the display manager service. Display adapters communicate changes in display device state to the display manager service asynchronously via a {@link DisplayAdapter.Listener} registered by the display manager service. This separation of concerns is important for two main reasons. First, it neatly encapsulates the responsibilities of these two classes: display adapters handle individual display devices whereas the display manager service handles the global state. Second, it eliminates the potential for deadlocks resulting from asynchronous display device discovery.

Synchronization

Because the display manager may be accessed by multiple threads, the synchronization story gets a little complicated. In particular, the window manager may call into the display manager while holding a surface transaction with the expectation that it can apply changes immediately. Unfortunately, that means we can't just do everything asynchronously (*grump*).

To make this work, all of the objects that belong to the display manager must use the same lock. We call this lock the synchronization root and it has a unique type {@link DisplayManagerService.SyncRoot}. Methods that require this lock are named with the "Locked" suffix.

Where things get tricky is that the display manager is not allowed to make any potentially reentrant calls, especially into the window manager. We generally avoid this by making all potentially reentrant out-calls asynchronous.

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
private static final String
FORCE_WIFI_DISPLAY_ENABLE
private static final long
WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT
private static final int
MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER
private static final int
MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS
private static final int
MSG_DELIVER_DISPLAY_EVENT
private static final int
MSG_REQUEST_TRAVERSAL
private static final int
MSG_UPDATE_VIEWPORT
private final android.content.Context
mContext
private final DisplayManagerHandler
mHandler
private final android.os.Handler
mUiHandler
private final DisplayAdapterListener
mDisplayAdapterListener
private android.view.WindowManagerInternal
mWindowManagerInternal
private android.hardware.input.InputManagerInternal
mInputManagerInternal
private android.media.projection.IMediaProjectionManager
mProjectionService
private final SyncRoot
mSyncRoot
public boolean
mSafeMode
public boolean
mOnlyCore
private final boolean
mSingleDisplayDemoMode
public final android.util.SparseArray
mCallbacks
private final ArrayList
mDisplayAdapters
private final ArrayList
mDisplayDevices
private final android.util.SparseArray
mLogicalDisplays
private int
mNextNonDefaultDisplayId
private final CopyOnWriteArrayList
mDisplayTransactionListeners
private DisplayPowerController
mDisplayPowerController
private int
mGlobalDisplayState
private boolean
mPendingTraversal
private WifiDisplayAdapter
mWifiDisplayAdapter
private int
mWifiDisplayScanRequestCount
private VirtualDisplayAdapter
mVirtualDisplayAdapter
private final android.hardware.display.DisplayViewport
mDefaultViewport
private final android.hardware.display.DisplayViewport
mExternalTouchViewport
private final PersistentDataStore
mPersistentDataStore
private final ArrayList
mTempCallbacks
private final android.view.DisplayInfo
mTempDisplayInfo
private final android.hardware.display.DisplayViewport
mTempDefaultViewport
private final android.hardware.display.DisplayViewport
mTempExternalTouchViewport
private final ArrayList
mTempDisplayStateWorkQueue
Constructors Summary
public DisplayManagerService(android.content.Context context)


       
        super(context);
        mContext = context;
        mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
        mUiHandler = UiThread.getHandler();
        mDisplayAdapterListener = new DisplayAdapterListener();
        mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
    
Methods Summary
private voidaddLogicalDisplayLocked(DisplayDevice device)

        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
        boolean isDefault = (deviceInfo.flags
                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
            isDefault = false;
        }

        if (!isDefault && mSingleDisplayDemoMode) {
            Slog.i(TAG, "Not creating a logical display for a secondary display "
                    + " because single display demo mode is enabled: " + deviceInfo);
            return;
        }

        final int displayId = assignDisplayIdLocked(isDefault);
        final int layerStack = assignLayerStackLocked(displayId);

        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
        display.updateLocked(mDisplayDevices);
        if (!display.isValidLocked()) {
            // This should never happen currently.
            Slog.w(TAG, "Ignoring display device because the logical display "
                    + "created from it was not considered valid: " + deviceInfo);
            return;
        }

        mLogicalDisplays.put(displayId, display);

        // Wake up waitForDefaultDisplay.
        if (isDefault) {
            mSyncRoot.notifyAll();
        }

        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
    
private intassignDisplayIdLocked(boolean isDefault)

        return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
    
private intassignLayerStackLocked(int displayId)

        // Currently layer stacks and display ids are the same.
        // This need not be the case.
        return displayId;
    
private voidclearViewportsLocked()

        mDefaultViewport.valid = false;
        mExternalTouchViewport.valid = false;
    
private voidconfigureDisplayInTransactionLocked(DisplayDevice device)

        final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
        final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;

        // Find the logical display that the display device is showing.
        // Certain displays only ever show their own content.
        LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
        if (!ownContent) {
            if (display != null && !display.hasContentLocked()) {
                // If the display does not have any content of its own, then
                // automatically mirror the default logical display contents.
                display = null;
            }
            if (display == null) {
                display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
            }
        }

        // Apply the logical display configuration to the display device.
        if (display == null) {
            // TODO: no logical display for the device, blank it
            Slog.w(TAG, "Missing logical display to use for physical display device: "
                    + device.getDisplayDeviceInfoLocked());
            return;
        }
        display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);

        // Update the viewports if needed.
        if (!mDefaultViewport.valid
                && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
            setViewportLocked(mDefaultViewport, display, device);
        }
        if (!mExternalTouchViewport.valid
                && info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
            setViewportLocked(mExternalTouchViewport, display, device);
        }
    
private voidconnectWifiDisplayInternal(java.lang.String address)

        synchronized (mSyncRoot) {
            if (mWifiDisplayAdapter != null) {
                mWifiDisplayAdapter.requestConnectLocked(address);
            }
        }
    
private intcreateVirtualDisplayInternal(android.hardware.display.IVirtualDisplayCallback callback, android.media.projection.IMediaProjection projection, int callingUid, java.lang.String packageName, java.lang.String name, int width, int height, int densityDpi, android.view.Surface surface, int flags)

        synchronized (mSyncRoot) {
            if (mVirtualDisplayAdapter == null) {
                Slog.w(TAG, "Rejecting request to create private virtual display "
                        + "because the virtual display adapter is not available.");
                return -1;
            }

            DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
                    callback, projection, callingUid, packageName,
                    name, width, height, densityDpi, surface, flags);
            if (device == null) {
                return -1;
            }

            handleDisplayDeviceAddedLocked(device);
            LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
            if (display != null) {
                return display.getDisplayIdLocked();
            }

            // Something weird happened and the logical display was not created.
            Slog.w(TAG, "Rejecting request to create virtual display "
                    + "because the logical display was not created.");
            mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder());
            handleDisplayDeviceRemovedLocked(device);
        }
        return -1;
    
private voiddeliverDisplayEvent(int displayId, int event)

        if (DEBUG) {
            Slog.d(TAG, "Delivering display event: displayId="
                    + displayId + ", event=" + event);
        }

        // Grab the lock and copy the callbacks.
        final int count;
        synchronized (mSyncRoot) {
            count = mCallbacks.size();
            mTempCallbacks.clear();
            for (int i = 0; i < count; i++) {
                mTempCallbacks.add(mCallbacks.valueAt(i));
            }
        }

        // After releasing the lock, send the notifications out.
        for (int i = 0; i < count; i++) {
            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
        }
        mTempCallbacks.clear();
    
private voiddisconnectWifiDisplayInternal()

        synchronized (mSyncRoot) {
            if (mWifiDisplayAdapter != null) {
                mWifiDisplayAdapter.requestDisconnectLocked();
            }
        }
    
private voiddumpInternal(java.io.PrintWriter pw)

        pw.println("DISPLAY MANAGER (dumpsys display)");

        synchronized (mSyncRoot) {
            pw.println("  mOnlyCode=" + mOnlyCore);
            pw.println("  mSafeMode=" + mSafeMode);
            pw.println("  mPendingTraversal=" + mPendingTraversal);
            pw.println("  mGlobalDisplayState=" + Display.stateToString(mGlobalDisplayState));
            pw.println("  mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
            pw.println("  mDefaultViewport=" + mDefaultViewport);
            pw.println("  mExternalTouchViewport=" + mExternalTouchViewport);
            pw.println("  mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
            pw.println("  mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);

            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
            ipw.increaseIndent();

            pw.println();
            pw.println("Display Adapters: size=" + mDisplayAdapters.size());
            for (DisplayAdapter adapter : mDisplayAdapters) {
                pw.println("  " + adapter.getName());
                adapter.dumpLocked(ipw);
            }

            pw.println();
            pw.println("Display Devices: size=" + mDisplayDevices.size());
            for (DisplayDevice device : mDisplayDevices) {
                pw.println("  " + device.getDisplayDeviceInfoLocked());
                device.dumpLocked(ipw);
            }

            final int logicalDisplayCount = mLogicalDisplays.size();
            pw.println();
            pw.println("Logical Displays: size=" + logicalDisplayCount);
            for (int i = 0; i < logicalDisplayCount; i++) {
                int displayId = mLogicalDisplays.keyAt(i);
                LogicalDisplay display = mLogicalDisplays.valueAt(i);
                pw.println("  Display " + displayId + ":");
                display.dumpLocked(ipw);
            }

            final int callbackCount = mCallbacks.size();
            pw.println();
            pw.println("Callbacks: size=" + callbackCount);
            for (int i = 0; i < callbackCount; i++) {
                CallbackRecord callback = mCallbacks.valueAt(i);
                pw.println("  " + i + ": mPid=" + callback.mPid
                        + ", mWifiDisplayScanRequested=" + callback.mWifiDisplayScanRequested);
            }

            if (mDisplayPowerController != null) {
                mDisplayPowerController.dump(pw);
            }
        }
    
private LogicalDisplayfindLogicalDisplayForDeviceLocked(DisplayDevice device)

        final int count = mLogicalDisplays.size();
        for (int i = 0; i < count; i++) {
            LogicalDisplay display = mLogicalDisplays.valueAt(i);
            if (display.getPrimaryDisplayDeviceLocked() == device) {
                return display;
            }
        }
        return null;
    
private voidforgetWifiDisplayInternal(java.lang.String address)

        synchronized (mSyncRoot) {
            if (mWifiDisplayAdapter != null) {
                mWifiDisplayAdapter.requestForgetLocked(address);
            }
        }
    
private int[]getDisplayIdsInternal(int callingUid)

        synchronized (mSyncRoot) {
            final int count = mLogicalDisplays.size();
            int[] displayIds = new int[count];
            int n = 0;
            for (int i = 0; i < count; i++) {
                LogicalDisplay display = mLogicalDisplays.valueAt(i);
                DisplayInfo info = display.getDisplayInfoLocked();
                if (info.hasAccess(callingUid)) {
                    displayIds[n++] = mLogicalDisplays.keyAt(i);
                }
            }
            if (n != count) {
                displayIds = Arrays.copyOfRange(displayIds, 0, n);
            }
            return displayIds;
        }
    
private android.view.DisplayInfogetDisplayInfoInternal(int displayId, int callingUid)

        synchronized (mSyncRoot) {
            LogicalDisplay display = mLogicalDisplays.get(displayId);
            if (display != null) {
                DisplayInfo info = display.getDisplayInfoLocked();
                if (info.hasAccess(callingUid)) {
                    return info;
                }
            }
            return null;
        }
    
private android.media.projection.IMediaProjectionManagergetProjectionService()

        if (mProjectionService == null) {
            IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
            mProjectionService = IMediaProjectionManager.Stub.asInterface(b);
        }
        return mProjectionService;
    
private android.hardware.display.WifiDisplayStatusgetWifiDisplayStatusInternal()

        synchronized (mSyncRoot) {
            if (mWifiDisplayAdapter != null) {
                return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
            }
            return new WifiDisplayStatus();
        }
    
private voidhandleDisplayDeviceAdded(DisplayDevice device)

        synchronized (mSyncRoot) {
            handleDisplayDeviceAddedLocked(device);
        }
    
private voidhandleDisplayDeviceAddedLocked(DisplayDevice device)

        if (mDisplayDevices.contains(device)) {
            Slog.w(TAG, "Attempted to add already added display device: "
                    + device.getDisplayDeviceInfoLocked());
            return;
        }

        Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());

        mDisplayDevices.add(device);
        addLogicalDisplayLocked(device);
        Runnable work = updateDisplayStateLocked(device);
        if (work != null) {
            work.run();
        }
        scheduleTraversalLocked(false);
    
private voidhandleDisplayDeviceChanged(DisplayDevice device)

        synchronized (mSyncRoot) {
            if (!mDisplayDevices.contains(device)) {
                Slog.w(TAG, "Attempted to change non-existent display device: "
                        + device.getDisplayDeviceInfoLocked());
                return;
            }

            Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());

            device.applyPendingDisplayDeviceInfoChangesLocked();
            if (updateLogicalDisplaysLocked()) {
                scheduleTraversalLocked(false);
            }
        }
    
private voidhandleDisplayDeviceRemoved(DisplayDevice device)

        synchronized (mSyncRoot) {
            handleDisplayDeviceRemovedLocked(device);
        }
    
private voidhandleDisplayDeviceRemovedLocked(DisplayDevice device)

        if (!mDisplayDevices.remove(device)) {
            Slog.w(TAG, "Attempted to remove non-existent display device: "
                    + device.getDisplayDeviceInfoLocked());
            return;
        }

        Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());

        updateLogicalDisplaysLocked();
        scheduleTraversalLocked(false);
    
public voidonBootPhase(int phase)

        if (phase == PHASE_WAIT_FOR_DEFAULT_DISPLAY) {
            synchronized (mSyncRoot) {
                long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
                while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
                    long delay = timeout - SystemClock.uptimeMillis();
                    if (delay <= 0) {
                        throw new RuntimeException("Timeout waiting for default display "
                                + "to be initialized.");
                    }
                    if (DEBUG) {
                        Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
                    }
                    try {
                        mSyncRoot.wait(delay);
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }
    
private voidonCallbackDied(com.android.server.display.DisplayManagerService$CallbackRecord record)

        synchronized (mSyncRoot) {
            mCallbacks.remove(record.mPid);
            stopWifiDisplayScanLocked(record);
        }
    
public voidonStart()

        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);

        publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
                true /*allowIsolated*/);
        publishLocalService(DisplayManagerInternal.class, new LocalService());
    
private voidpauseWifiDisplayInternal()

        synchronized (mSyncRoot) {
            if (mWifiDisplayAdapter != null) {
                mWifiDisplayAdapter.requestPauseLocked();
            }
        }
    
private voidperformTraversalInTransactionFromWindowManagerInternal()

        synchronized (mSyncRoot) {
            if (!mPendingTraversal) {
                return;
            }
            mPendingTraversal = false;

            performTraversalInTransactionLocked();
        }

        // List is self-synchronized copy-on-write.
        for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
            listener.onDisplayTransaction();
        }
    
private voidperformTraversalInTransactionLocked()

        // Clear all viewports before configuring displays so that we can keep
        // track of which ones we have configured.
        clearViewportsLocked();

        // Configure each display device.
        final int count = mDisplayDevices.size();
        for (int i = 0; i < count; i++) {
            DisplayDevice device = mDisplayDevices.get(i);
            configureDisplayInTransactionLocked(device);
            device.performTraversalInTransactionLocked();
        }

        // Tell the input system about these new viewports.
        if (mInputManagerInternal != null) {
            mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
        }
    
private voidregisterAdditionalDisplayAdapters()

        synchronized (mSyncRoot) {
            if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
                registerOverlayDisplayAdapterLocked();
                registerWifiDisplayAdapterLocked();
                registerVirtualDisplayAdapterLocked();
            }
        }
    
private voidregisterCallbackInternal(android.hardware.display.IDisplayManagerCallback callback, int callingPid)

        synchronized (mSyncRoot) {
            if (mCallbacks.get(callingPid) != null) {
                throw new SecurityException("The calling process has already "
                        + "registered an IDisplayManagerCallback.");
            }

            CallbackRecord record = new CallbackRecord(callingPid, callback);
            try {
                IBinder binder = callback.asBinder();
                binder.linkToDeath(record, 0);
            } catch (RemoteException ex) {
                // give up
                throw new RuntimeException(ex);
            }

            mCallbacks.put(callingPid, record);
        }
    
private voidregisterDefaultDisplayAdapter()

        // Register default display adapter.
        synchronized (mSyncRoot) {
            registerDisplayAdapterLocked(new LocalDisplayAdapter(
                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
        }
    
private voidregisterDisplayAdapterLocked(DisplayAdapter adapter)

        mDisplayAdapters.add(adapter);
        adapter.registerLocked();
    
private voidregisterDisplayTransactionListenerInternal(android.hardware.display.DisplayManagerInternal.DisplayTransactionListener listener)

        // List is self-synchronized copy-on-write.
        mDisplayTransactionListeners.add(listener);
    
private voidregisterOverlayDisplayAdapterLocked()

        registerDisplayAdapterLocked(new OverlayDisplayAdapter(
                mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
    
private voidregisterVirtualDisplayAdapterLocked()

        mVirtualDisplayAdapter = new VirtualDisplayAdapter(
                mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
        registerDisplayAdapterLocked(mVirtualDisplayAdapter);
    
private voidregisterWifiDisplayAdapterLocked()

        if (mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_enableWifiDisplay)
                || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) {
            mWifiDisplayAdapter = new WifiDisplayAdapter(
                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener,
                    mPersistentDataStore);
            registerDisplayAdapterLocked(mWifiDisplayAdapter);
        }
    
private voidreleaseVirtualDisplayInternal(android.os.IBinder appToken)

        synchronized (mSyncRoot) {
            if (mVirtualDisplayAdapter == null) {
                return;
            }

            DisplayDevice device =
                    mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
            if (device != null) {
                handleDisplayDeviceRemovedLocked(device);
            }
        }
    
private voidrenameWifiDisplayInternal(java.lang.String address, java.lang.String alias)

        synchronized (mSyncRoot) {
            if (mWifiDisplayAdapter != null) {
                mWifiDisplayAdapter.requestRenameLocked(address, alias);
            }
        }
    
private voidrequestGlobalDisplayStateInternal(int state)

        synchronized (mTempDisplayStateWorkQueue) {
            try {
                // Update the display state within the lock.
                synchronized (mSyncRoot) {
                    if (mGlobalDisplayState != state) {
                        mGlobalDisplayState = state;
                        updateGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
                        scheduleTraversalLocked(false);
                    }
                }

                // Setting the display power state can take hundreds of milliseconds
                // to complete so we defer the most expensive part of the work until
                // after we have exited the critical section to avoid blocking other
                // threads for a long time.
                for (int i = 0; i < mTempDisplayStateWorkQueue.size(); i++) {
                    mTempDisplayStateWorkQueue.get(i).run();
                }
            } finally {
                mTempDisplayStateWorkQueue.clear();
            }
        }
    
private voidresizeVirtualDisplayInternal(android.os.IBinder appToken, int width, int height, int densityDpi)

        synchronized (mSyncRoot) {
            if (mVirtualDisplayAdapter == null) {
                return;
            }

            mVirtualDisplayAdapter.resizeVirtualDisplayLocked(appToken, width, height, densityDpi);
        }
    
private voidresumeWifiDisplayInternal()

        synchronized (mSyncRoot) {
            if (mWifiDisplayAdapter != null) {
                mWifiDisplayAdapter.requestResumeLocked();
            }
        }
    
private voidscheduleTraversalLocked(boolean inTraversal)

        if (!mPendingTraversal && mWindowManagerInternal != null) {
            mPendingTraversal = true;
            if (!inTraversal) {
                mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
            }
        }
    
private voidsendDisplayEventLocked(int displayId, int event)

        Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
        mHandler.sendMessage(msg);
    
private voidsetDisplayInfoOverrideFromWindowManagerInternal(int displayId, android.view.DisplayInfo info)

        synchronized (mSyncRoot) {
            LogicalDisplay display = mLogicalDisplays.get(displayId);
            if (display != null) {
                if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
                    sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
                    scheduleTraversalLocked(false);
                }
            }
        }
    
private voidsetDisplayPropertiesInternal(int displayId, boolean hasContent, float requestedRefreshRate, boolean inTraversal)

        synchronized (mSyncRoot) {
            LogicalDisplay display = mLogicalDisplays.get(displayId);
            if (display == null) {
                return;
            }
            if (display.hasContentLocked() != hasContent) {
                if (DEBUG) {
                    Slog.d(TAG, "Display " + displayId + " hasContent flag changed: "
                            + "hasContent=" + hasContent + ", inTraversal=" + inTraversal);
                }

                display.setHasContentLocked(hasContent);
                scheduleTraversalLocked(inTraversal);
            }
            if (display.getRequestedRefreshRateLocked() != requestedRefreshRate) {
                if (DEBUG) {
                    Slog.d(TAG, "Display " + displayId + " has requested a new refresh rate: "
                            + requestedRefreshRate + "fps");
                }
                display.setRequestedRefreshRateLocked(requestedRefreshRate);
                scheduleTraversalLocked(inTraversal);
            }
        }
    
private static voidsetViewportLocked(android.hardware.display.DisplayViewport viewport, LogicalDisplay display, DisplayDevice device)

        viewport.valid = true;
        viewport.displayId = display.getDisplayIdLocked();
        device.populateViewportLocked(viewport);
    
private voidsetVirtualDisplaySurfaceInternal(android.os.IBinder appToken, android.view.Surface surface)

        synchronized (mSyncRoot) {
            if (mVirtualDisplayAdapter == null) {
                return;
            }

            mVirtualDisplayAdapter.setVirtualDisplaySurfaceLocked(appToken, surface);
        }
    
private booleanshouldRegisterNonEssentialDisplayAdaptersLocked()

        // In safe mode, we disable non-essential display adapters to give the user
        // an opportunity to fix broken settings or other problems that might affect
        // system stability.
        // In only-core mode, we disable non-essential display adapters to minimize
        // the number of dependencies that are started while in this mode and to
        // prevent problems that might occur due to the device being encrypted.
        return !mSafeMode && !mOnlyCore;
    
private voidstartWifiDisplayScanInternal(int callingPid)

        synchronized (mSyncRoot) {
            CallbackRecord record = mCallbacks.get(callingPid);
            if (record == null) {
                throw new IllegalStateException("The calling process has not "
                        + "registered an IDisplayManagerCallback.");
            }
            startWifiDisplayScanLocked(record);
        }
    
private voidstartWifiDisplayScanLocked(com.android.server.display.DisplayManagerService$CallbackRecord record)

        if (!record.mWifiDisplayScanRequested) {
            record.mWifiDisplayScanRequested = true;
            if (mWifiDisplayScanRequestCount++ == 0) {
                if (mWifiDisplayAdapter != null) {
                    mWifiDisplayAdapter.requestStartScanLocked();
                }
            }
        }
    
private voidstopWifiDisplayScanInternal(int callingPid)

        synchronized (mSyncRoot) {
            CallbackRecord record = mCallbacks.get(callingPid);
            if (record == null) {
                throw new IllegalStateException("The calling process has not "
                        + "registered an IDisplayManagerCallback.");
            }
            stopWifiDisplayScanLocked(record);
        }
    
private voidstopWifiDisplayScanLocked(com.android.server.display.DisplayManagerService$CallbackRecord record)

        if (record.mWifiDisplayScanRequested) {
            record.mWifiDisplayScanRequested = false;
            if (--mWifiDisplayScanRequestCount == 0) {
                if (mWifiDisplayAdapter != null) {
                    mWifiDisplayAdapter.requestStopScanLocked();
                }
            } else if (mWifiDisplayScanRequestCount < 0) {
                Slog.wtf(TAG, "mWifiDisplayScanRequestCount became negative: "
                        + mWifiDisplayScanRequestCount);
                mWifiDisplayScanRequestCount = 0;
            }
        }
    
public voidsystemReady(boolean safeMode, boolean onlyCore)
Called when the system is ready to go.

        synchronized (mSyncRoot) {
            mSafeMode = safeMode;
            mOnlyCore = onlyCore;
        }

        mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
    
private voidunregisterDisplayTransactionListenerInternal(android.hardware.display.DisplayManagerInternal.DisplayTransactionListener listener)

        // List is self-synchronized copy-on-write.
        mDisplayTransactionListeners.remove(listener);
    
private java.lang.RunnableupdateDisplayStateLocked(DisplayDevice device)

        // Blank or unblank the display immediately to match the state requested
        // by the display power controller (if known).
        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
        if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
            return device.requestDisplayStateLocked(mGlobalDisplayState);
        }
        return null;
    
private voidupdateGlobalDisplayStateLocked(java.util.List workQueue)

        final int count = mDisplayDevices.size();
        for (int i = 0; i < count; i++) {
            DisplayDevice device = mDisplayDevices.get(i);
            Runnable runnable = updateDisplayStateLocked(device);
            if (runnable != null) {
                workQueue.add(runnable);
            }
        }
    
private booleanupdateLogicalDisplaysLocked()

        boolean changed = false;
        for (int i = mLogicalDisplays.size(); i-- > 0; ) {
            final int displayId = mLogicalDisplays.keyAt(i);
            LogicalDisplay display = mLogicalDisplays.valueAt(i);

            mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
            display.updateLocked(mDisplayDevices);
            if (!display.isValidLocked()) {
                mLogicalDisplays.removeAt(i);
                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
                changed = true;
            } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
                changed = true;
            }
        }
        return changed;
    
public voidwindowManagerAndInputReady()

        synchronized (mSyncRoot) {
            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
            mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
            scheduleTraversalLocked(false);
        }