Loading services/core/java/com/android/server/display/DisplayDeviceRepository.java 0 → 100644 +149 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.display; import android.annotation.NonNull; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.server.display.DisplayManagerService.SyncRoot; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; /** * Container for all the display devices present in the system. If an object wants to get events * about all the DisplayDevices without needing to listen to all of the DisplayAdapters, they can * listen and interact with the instance of this class. * <p> * The collection of {@link DisplayDevice}s and their usage is protected by the provided * {@link DisplayManagerService.SyncRoot} lock object. */ class DisplayDeviceRepository implements DisplayAdapter.Listener { private static final String TAG = "DisplayDeviceRepository"; public static final int DISPLAY_DEVICE_EVENT_ADDED = 1; public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2; public static final int DISPLAY_DEVICE_EVENT_REMOVED = 3; /** * List of all currently connected display devices. Indexed by the displayId. * TODO: multi-display - break the notion that this is indexed by displayId. */ @GuardedBy("mSyncRoot") private final List<DisplayDevice> mDisplayDevices = new ArrayList<>(); /** Listener for {link DisplayDevice} events. */ private final Listener mListener; /** Global lock object from {@link DisplayManagerService}. */ private final SyncRoot mSyncRoot; DisplayDeviceRepository(@NonNull SyncRoot syncRoot, @NonNull Listener listener) { mSyncRoot = syncRoot; mListener = listener; } @Override public void onDisplayDeviceEvent(DisplayDevice device, int event) { switch (event) { case DISPLAY_DEVICE_EVENT_ADDED: handleDisplayDeviceAdded(device); break; case DISPLAY_DEVICE_EVENT_CHANGED: handleDisplayDeviceChanged(device); break; case DISPLAY_DEVICE_EVENT_REMOVED: handleDisplayDeviceRemoved(device); break; } } @Override public void onTraversalRequested() { mListener.onTraversalRequested(); } public boolean containsLocked(DisplayDevice d) { return mDisplayDevices.contains(d); } public int sizeLocked() { return mDisplayDevices.size(); } public void forEachLocked(Consumer<DisplayDevice> consumer) { final int count = mDisplayDevices.size(); for (int i = 0; i < count; i++) { consumer.accept(mDisplayDevices.get(i)); } } private void handleDisplayDeviceAdded(DisplayDevice device) { synchronized (mSyncRoot) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (mDisplayDevices.contains(device)) { Slog.w(TAG, "Attempted to add already added display device: " + info); return; } Slog.i(TAG, "Display device added: " + info); device.mDebugLastLoggedDeviceInfo = info; mDisplayDevices.add(device); mListener.onDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); } } private void handleDisplayDeviceChanged(DisplayDevice device) { synchronized (mSyncRoot) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (!mDisplayDevices.contains(device)) { Slog.w(TAG, "Attempted to change non-existent display device: " + info); return; } mListener.onDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED); } } private void handleDisplayDeviceRemoved(DisplayDevice device) { synchronized (mSyncRoot) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (!mDisplayDevices.remove(device)) { Slog.w(TAG, "Attempted to remove non-existent display device: " + info); return; } Slog.i(TAG, "Display device removed: " + info); device.mDebugLastLoggedDeviceInfo = info; mListener.onDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED); } } /** * Listens to {@link DisplayDevice} events from {@link DisplayDeviceRepository}. */ interface Listener { void onDisplayDeviceEventLocked(DisplayDevice device, int event); // TODO: multi-display - Try to remove the need for requestTraversal...it feels like // a shoe-horned method for a shoe-horned feature. void onTraversalRequested(); }; } services/core/java/com/android/server/display/DisplayManagerService.java +86 −88 Original line number Diff line number Diff line Loading @@ -131,7 +131,8 @@ import java.util.concurrent.CopyOnWriteArrayList; * </p><p> * 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 * service asynchronously via a {@link DisplayAdapter.Listener}, and through * the {@link DisplayDeviceRepository.Listener}, which is ultimately 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 Loading Loading @@ -180,7 +181,7 @@ public final class DisplayManagerService extends SystemService { private final Context mContext; private final DisplayManagerHandler mHandler; private final Handler mUiHandler; private final DisplayAdapterListener mDisplayAdapterListener; private final DisplayDeviceListener mDisplayDeviceListener; private final DisplayModeDirector mDisplayModeDirector; private WindowManagerInternal mWindowManagerInternal; private InputManagerInternal mInputManagerInternal; Loading Loading @@ -215,8 +216,7 @@ public final class DisplayManagerService extends SystemService { // List of all currently registered display adapters. private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>(); // List of all currently connected display devices. private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>(); private final DisplayDeviceRepository mDisplayDeviceRepo; // List of all logical displays indexed by logical display id. // Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache. Loading Loading @@ -331,7 +331,8 @@ public final class DisplayManagerService extends SystemService { mContext = context; mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper()); mUiHandler = UiThread.getHandler(); mDisplayAdapterListener = new DisplayAdapterListener(); mDisplayDeviceListener = new DisplayDeviceListener(); mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mDisplayDeviceListener); mDisplayModeDirector = new DisplayModeDirector(context, mHandler); mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); Resources resources = mContext.getResources(); Loading Loading @@ -469,6 +470,11 @@ public final class DisplayManagerService extends SystemService { return mHandler; } @VisibleForTesting DisplayDeviceRepository getDisplayDeviceRepository() { return mDisplayDeviceRepo; } private void loadStableDisplayValuesLocked() { final Point size = mPersistentDataStore.getStableDisplaySize(); if (size.x > 0 && size.y > 0) { Loading Loading @@ -818,7 +824,17 @@ public final class DisplayManagerService extends SystemService { return -1; } handleDisplayDeviceAddedLocked(device); // DisplayDevice events are handled manually for Virtual Displays. // TODO: multi-display Fix this so that generic add/remove events are not handled in a // different code path for virtual displays. Currently this happens so that we can // return a valid display ID synchronously upon successful Virtual Display creation. // This code can run on any binder thread, while onDisplayDeviceAdded() callbacks are // called on the DisplayThread (which we don't want to wait for?). // One option would be to actually wait here on the binder thread // to be notified when the virtual display is created (or failed). mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); LogicalDisplay display = findLogicalDisplayForDeviceLocked(device); if (display != null) { return display.getDisplayIdLocked(); Loading @@ -828,7 +844,8 @@ public final class DisplayManagerService extends SystemService { Slog.w(TAG, "Rejecting request to create virtual display " + "because the logical display was not created."); mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder()); handleDisplayDeviceRemovedLocked(device); mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED); } return -1; } Loading Loading @@ -863,7 +880,9 @@ public final class DisplayManagerService extends SystemService { DisplayDevice device = mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken); if (device != null) { handleDisplayDeviceRemovedLocked(device); // TODO - handle virtual displays the same as other display adapters. mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED); } } } Loading @@ -883,7 +902,7 @@ public final class DisplayManagerService extends SystemService { synchronized (mSyncRoot) { // main display adapter registerDisplayAdapterLocked(new LocalDisplayAdapter( mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); mSyncRoot, mContext, mHandler, mDisplayDeviceRepo)); // Standalone VR devices rely on a virtual display as their primary display for // 2D UI. We register virtual display adapter along side the main display adapter Loading @@ -891,7 +910,7 @@ public final class DisplayManagerService extends SystemService { // early apps like SetupWizard/Launcher. In particular, SUW is displayed using // the virtual display inside VR before any VR-specific apps even run. mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext, mHandler, mDisplayAdapterListener); mHandler, mDisplayDeviceRepo); if (mVirtualDisplayAdapter != null) { registerDisplayAdapterLocked(mVirtualDisplayAdapter); } Loading @@ -909,7 +928,7 @@ public final class DisplayManagerService extends SystemService { private void registerOverlayDisplayAdapterLocked() { registerDisplayAdapterLocked(new OverlayDisplayAdapter( mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler)); mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mUiHandler)); } private void registerWifiDisplayAdapterLocked() { Loading @@ -917,7 +936,7 @@ public final class DisplayManagerService extends SystemService { com.android.internal.R.bool.config_enableWifiDisplay) || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) { mWifiDisplayAdapter = new WifiDisplayAdapter( mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mPersistentDataStore); registerDisplayAdapterLocked(mWifiDisplayAdapter); } Loading Loading @@ -946,15 +965,6 @@ public final class DisplayManagerService extends SystemService { } private void handleDisplayDeviceAddedLocked(DisplayDevice device) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (mDisplayDevices.contains(device)) { Slog.w(TAG, "Attempted to add already added display device: " + info); return; } Slog.i(TAG, "Display device added: " + info); device.mDebugLastLoggedDeviceInfo = info; mDisplayDevices.add(device); LogicalDisplay display = addLogicalDisplayLocked(device); Runnable work = updateDisplayStateLocked(device); if (work != null) { Loading @@ -966,11 +976,12 @@ public final class DisplayManagerService extends SystemService { @VisibleForTesting void handleDisplayDeviceChanged(DisplayDevice device) { synchronized (mSyncRoot) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (!mDisplayDevices.contains(device)) { Slog.w(TAG, "Attempted to change non-existent display device: " + info); return; handleDisplayDeviceChangedLocked(device); } } private void handleDisplayDeviceChangedLocked(DisplayDevice device) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); int diff = device.mDebugLastLoggedDeviceInfo.diff(info); if (diff == DisplayDeviceInfo.DIFF_STATE) { Loading Loading @@ -1005,7 +1016,6 @@ public final class DisplayManagerService extends SystemService { scheduleTraversalLocked(false); } } } private void handleDisplayDeviceRemoved(DisplayDevice device) { synchronized (mSyncRoot) { Loading @@ -1014,15 +1024,6 @@ public final class DisplayManagerService extends SystemService { } private void handleDisplayDeviceRemovedLocked(DisplayDevice device) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (!mDisplayDevices.remove(device)) { Slog.w(TAG, "Attempted to remove non-existent display device: " + info); return; } Slog.i(TAG, "Display device removed: " + info); device.mDebugLastLoggedDeviceInfo = info; updateLogicalDisplaysLocked(); scheduleTraversalLocked(false); } Loading @@ -1043,14 +1044,12 @@ public final class DisplayManagerService extends SystemService { } private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) { final int count = mDisplayDevices.size(); for (int i = 0; i < count; i++) { DisplayDevice device = mDisplayDevices.get(i); mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> { Runnable runnable = updateDisplayStateLocked(device); if (runnable != null) { workQueue.add(runnable); } } }); } private Runnable updateDisplayStateLocked(DisplayDevice device) { Loading @@ -1058,6 +1057,8 @@ public final class DisplayManagerService extends SystemService { // by the display power controller (if known). DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { // TODO - multi-display - The rules regarding what display state to apply to each // display will depend on the configuration/mapping of logical displays. return device.requestDisplayStateLocked( mGlobalDisplayState, mGlobalDisplayBrightness); } Loading Loading @@ -1085,7 +1086,7 @@ public final class DisplayManagerService extends SystemService { final int layerStack = assignLayerStackLocked(displayId); LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device); display.updateLocked(mDisplayDevices); display.updateLocked(mDisplayDeviceRepo); if (!display.isValidLocked()) { // This should never happen currently. Slog.w(TAG, "Ignoring display device because the logical display " Loading Loading @@ -1248,7 +1249,7 @@ public final class DisplayManagerService extends SystemService { mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked()); display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo); display.updateLocked(mDisplayDevices); display.updateLocked(mDisplayDeviceRepo); if (!display.isValidLocked()) { mLogicalDisplays.removeAt(i); handleLogicalDisplayRemoved(displayId); Loading Loading @@ -1276,12 +1277,10 @@ public final class DisplayManagerService extends SystemService { clearViewportsLocked(); // Configure each display device. final int count = mDisplayDevices.size(); for (int i = 0; i < count; i++) { DisplayDevice device = mDisplayDevices.get(i); mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> { configureDisplayLocked(t, device); device.performTraversalLocked(t); } }); // Tell the input system about these new viewports. if (mInputManagerInternal != null) { Loading Loading @@ -1714,11 +1713,11 @@ public final class DisplayManagerService extends SystemService { } pw.println(); pw.println("Display Devices: size=" + mDisplayDevices.size()); for (DisplayDevice device : mDisplayDevices) { pw.println("Display Devices: size=" + mDisplayDeviceRepo.sizeLocked()); mDisplayDeviceRepo.forEachLocked(device -> { pw.println(" " + device.getDisplayDeviceInfoLocked()); device.dumpLocked(ipw); } }); final int logicalDisplayCount = mLogicalDisplays.size(); pw.println(); Loading Loading @@ -1864,20 +1863,20 @@ public final class DisplayManagerService extends SystemService { } } private final class DisplayAdapterListener implements DisplayAdapter.Listener { private final class DisplayDeviceListener implements DisplayDeviceRepository.Listener { @Override public void onDisplayDeviceEvent(DisplayDevice device, int event) { public void onDisplayDeviceEventLocked(DisplayDevice device, int event) { switch (event) { case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED: handleDisplayDeviceAdded(device); case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_ADDED: handleDisplayDeviceAddedLocked(device); break; case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED: handleDisplayDeviceChanged(device); case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_CHANGED: handleDisplayDeviceChangedLocked(device); break; case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED: handleDisplayDeviceRemoved(device); case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED: handleDisplayDeviceRemovedLocked(device); break; } } Loading Loading @@ -2573,9 +2572,10 @@ public final class DisplayManagerService extends SystemService { } } }; LogicalDisplay defaultDisplay = mLogicalDisplays.get(Display.DEFAULT_DISPLAY); DisplayDevice defaultDevice = defaultDisplay.getPrimaryDisplayDeviceLocked(); mDisplayPowerController = new DisplayPowerController( mContext, callbacks, handler, sensorManager, blanker, mDisplayDevices.get(Display.DEFAULT_DISPLAY)); mContext, callbacks, handler, sensorManager, blanker, defaultDevice); mSensorManager = sensorManager; } Loading Loading @@ -2689,9 +2689,7 @@ public final class DisplayManagerService extends SystemService { @Override public void onOverlayChanged() { synchronized (mSyncRoot) { for (int i = 0; i < mDisplayDevices.size(); i++) { mDisplayDevices.get(i).onOverlayChangedLocked(); } mDisplayDeviceRepo.forEachLocked(DisplayDevice::onOverlayChangedLocked); } } Loading services/core/java/com/android/server/display/LogicalDisplay.java +3 −4 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import com.android.server.wm.utils.InsetUtils; import java.io.PrintWriter; import java.util.Arrays; import java.util.List; import java.util.Objects; /** Loading Loading @@ -220,16 +219,16 @@ final class LogicalDisplay { * The logical display might become invalid if it is attached to a display device * that no longer exists. * * @param devices The list of all connected display devices. * @param deviceRepo Repository of active {@link DisplayDevice}s. */ public void updateLocked(List<DisplayDevice> devices) { public void updateLocked(DisplayDeviceRepository deviceRepo) { // Nothing to update if already invalid. if (mPrimaryDisplayDevice == null) { return; } // Check whether logical display has become invalid. if (!devices.contains(mPrimaryDisplayDevice)) { if (!deviceRepo.containsLocked(mPrimaryDisplayDevice)) { mPrimaryDisplayDevice = null; return; } Loading services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -309,7 +309,8 @@ public class DisplayManagerServiceTest { zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect); displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY; displayDevice.setDisplayDeviceInfo(displayDeviceInfo); displayManager.handleDisplayDeviceAdded(displayDevice); displayManager.getDisplayDeviceRepository() .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); // Find the display id of the added FakeDisplayDevice DisplayManagerService.BinderService bs = displayManager.new BinderService(); Loading services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java +10 −5 Original line number Diff line number Diff line Loading @@ -28,8 +28,6 @@ import android.view.SurfaceControl; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; public class LogicalDisplayTest { private static final int DISPLAY_ID = 0; private static final int LAYER_STACK = 0; Loading @@ -51,9 +49,16 @@ public class LogicalDisplayTest { mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice); when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(displayDeviceInfo); ArrayList<DisplayDevice> displayDevices = new ArrayList<>(); displayDevices.add(mDisplayDevice); mLogicalDisplay.updateLocked(displayDevices); DisplayDeviceRepository repo = new DisplayDeviceRepository( new DisplayManagerService.SyncRoot(), new DisplayDeviceRepository.Listener() { @Override public void onDisplayDeviceEventLocked(DisplayDevice device, int event) {} @Override public void onTraversalRequested() {} }); repo.onDisplayDeviceEvent(mDisplayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); mLogicalDisplay.updateLocked(repo); } @Test Loading Loading
services/core/java/com/android/server/display/DisplayDeviceRepository.java 0 → 100644 +149 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.display; import android.annotation.NonNull; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.server.display.DisplayManagerService.SyncRoot; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; /** * Container for all the display devices present in the system. If an object wants to get events * about all the DisplayDevices without needing to listen to all of the DisplayAdapters, they can * listen and interact with the instance of this class. * <p> * The collection of {@link DisplayDevice}s and their usage is protected by the provided * {@link DisplayManagerService.SyncRoot} lock object. */ class DisplayDeviceRepository implements DisplayAdapter.Listener { private static final String TAG = "DisplayDeviceRepository"; public static final int DISPLAY_DEVICE_EVENT_ADDED = 1; public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2; public static final int DISPLAY_DEVICE_EVENT_REMOVED = 3; /** * List of all currently connected display devices. Indexed by the displayId. * TODO: multi-display - break the notion that this is indexed by displayId. */ @GuardedBy("mSyncRoot") private final List<DisplayDevice> mDisplayDevices = new ArrayList<>(); /** Listener for {link DisplayDevice} events. */ private final Listener mListener; /** Global lock object from {@link DisplayManagerService}. */ private final SyncRoot mSyncRoot; DisplayDeviceRepository(@NonNull SyncRoot syncRoot, @NonNull Listener listener) { mSyncRoot = syncRoot; mListener = listener; } @Override public void onDisplayDeviceEvent(DisplayDevice device, int event) { switch (event) { case DISPLAY_DEVICE_EVENT_ADDED: handleDisplayDeviceAdded(device); break; case DISPLAY_DEVICE_EVENT_CHANGED: handleDisplayDeviceChanged(device); break; case DISPLAY_DEVICE_EVENT_REMOVED: handleDisplayDeviceRemoved(device); break; } } @Override public void onTraversalRequested() { mListener.onTraversalRequested(); } public boolean containsLocked(DisplayDevice d) { return mDisplayDevices.contains(d); } public int sizeLocked() { return mDisplayDevices.size(); } public void forEachLocked(Consumer<DisplayDevice> consumer) { final int count = mDisplayDevices.size(); for (int i = 0; i < count; i++) { consumer.accept(mDisplayDevices.get(i)); } } private void handleDisplayDeviceAdded(DisplayDevice device) { synchronized (mSyncRoot) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (mDisplayDevices.contains(device)) { Slog.w(TAG, "Attempted to add already added display device: " + info); return; } Slog.i(TAG, "Display device added: " + info); device.mDebugLastLoggedDeviceInfo = info; mDisplayDevices.add(device); mListener.onDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); } } private void handleDisplayDeviceChanged(DisplayDevice device) { synchronized (mSyncRoot) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (!mDisplayDevices.contains(device)) { Slog.w(TAG, "Attempted to change non-existent display device: " + info); return; } mListener.onDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED); } } private void handleDisplayDeviceRemoved(DisplayDevice device) { synchronized (mSyncRoot) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (!mDisplayDevices.remove(device)) { Slog.w(TAG, "Attempted to remove non-existent display device: " + info); return; } Slog.i(TAG, "Display device removed: " + info); device.mDebugLastLoggedDeviceInfo = info; mListener.onDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED); } } /** * Listens to {@link DisplayDevice} events from {@link DisplayDeviceRepository}. */ interface Listener { void onDisplayDeviceEventLocked(DisplayDevice device, int event); // TODO: multi-display - Try to remove the need for requestTraversal...it feels like // a shoe-horned method for a shoe-horned feature. void onTraversalRequested(); }; }
services/core/java/com/android/server/display/DisplayManagerService.java +86 −88 Original line number Diff line number Diff line Loading @@ -131,7 +131,8 @@ import java.util.concurrent.CopyOnWriteArrayList; * </p><p> * 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 * service asynchronously via a {@link DisplayAdapter.Listener}, and through * the {@link DisplayDeviceRepository.Listener}, which is ultimately 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 Loading Loading @@ -180,7 +181,7 @@ public final class DisplayManagerService extends SystemService { private final Context mContext; private final DisplayManagerHandler mHandler; private final Handler mUiHandler; private final DisplayAdapterListener mDisplayAdapterListener; private final DisplayDeviceListener mDisplayDeviceListener; private final DisplayModeDirector mDisplayModeDirector; private WindowManagerInternal mWindowManagerInternal; private InputManagerInternal mInputManagerInternal; Loading Loading @@ -215,8 +216,7 @@ public final class DisplayManagerService extends SystemService { // List of all currently registered display adapters. private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>(); // List of all currently connected display devices. private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>(); private final DisplayDeviceRepository mDisplayDeviceRepo; // List of all logical displays indexed by logical display id. // Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache. Loading Loading @@ -331,7 +331,8 @@ public final class DisplayManagerService extends SystemService { mContext = context; mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper()); mUiHandler = UiThread.getHandler(); mDisplayAdapterListener = new DisplayAdapterListener(); mDisplayDeviceListener = new DisplayDeviceListener(); mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mDisplayDeviceListener); mDisplayModeDirector = new DisplayModeDirector(context, mHandler); mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); Resources resources = mContext.getResources(); Loading Loading @@ -469,6 +470,11 @@ public final class DisplayManagerService extends SystemService { return mHandler; } @VisibleForTesting DisplayDeviceRepository getDisplayDeviceRepository() { return mDisplayDeviceRepo; } private void loadStableDisplayValuesLocked() { final Point size = mPersistentDataStore.getStableDisplaySize(); if (size.x > 0 && size.y > 0) { Loading Loading @@ -818,7 +824,17 @@ public final class DisplayManagerService extends SystemService { return -1; } handleDisplayDeviceAddedLocked(device); // DisplayDevice events are handled manually for Virtual Displays. // TODO: multi-display Fix this so that generic add/remove events are not handled in a // different code path for virtual displays. Currently this happens so that we can // return a valid display ID synchronously upon successful Virtual Display creation. // This code can run on any binder thread, while onDisplayDeviceAdded() callbacks are // called on the DisplayThread (which we don't want to wait for?). // One option would be to actually wait here on the binder thread // to be notified when the virtual display is created (or failed). mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); LogicalDisplay display = findLogicalDisplayForDeviceLocked(device); if (display != null) { return display.getDisplayIdLocked(); Loading @@ -828,7 +844,8 @@ public final class DisplayManagerService extends SystemService { Slog.w(TAG, "Rejecting request to create virtual display " + "because the logical display was not created."); mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder()); handleDisplayDeviceRemovedLocked(device); mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED); } return -1; } Loading Loading @@ -863,7 +880,9 @@ public final class DisplayManagerService extends SystemService { DisplayDevice device = mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken); if (device != null) { handleDisplayDeviceRemovedLocked(device); // TODO - handle virtual displays the same as other display adapters. mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED); } } } Loading @@ -883,7 +902,7 @@ public final class DisplayManagerService extends SystemService { synchronized (mSyncRoot) { // main display adapter registerDisplayAdapterLocked(new LocalDisplayAdapter( mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); mSyncRoot, mContext, mHandler, mDisplayDeviceRepo)); // Standalone VR devices rely on a virtual display as their primary display for // 2D UI. We register virtual display adapter along side the main display adapter Loading @@ -891,7 +910,7 @@ public final class DisplayManagerService extends SystemService { // early apps like SetupWizard/Launcher. In particular, SUW is displayed using // the virtual display inside VR before any VR-specific apps even run. mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext, mHandler, mDisplayAdapterListener); mHandler, mDisplayDeviceRepo); if (mVirtualDisplayAdapter != null) { registerDisplayAdapterLocked(mVirtualDisplayAdapter); } Loading @@ -909,7 +928,7 @@ public final class DisplayManagerService extends SystemService { private void registerOverlayDisplayAdapterLocked() { registerDisplayAdapterLocked(new OverlayDisplayAdapter( mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler)); mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mUiHandler)); } private void registerWifiDisplayAdapterLocked() { Loading @@ -917,7 +936,7 @@ public final class DisplayManagerService extends SystemService { com.android.internal.R.bool.config_enableWifiDisplay) || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) { mWifiDisplayAdapter = new WifiDisplayAdapter( mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mPersistentDataStore); registerDisplayAdapterLocked(mWifiDisplayAdapter); } Loading Loading @@ -946,15 +965,6 @@ public final class DisplayManagerService extends SystemService { } private void handleDisplayDeviceAddedLocked(DisplayDevice device) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (mDisplayDevices.contains(device)) { Slog.w(TAG, "Attempted to add already added display device: " + info); return; } Slog.i(TAG, "Display device added: " + info); device.mDebugLastLoggedDeviceInfo = info; mDisplayDevices.add(device); LogicalDisplay display = addLogicalDisplayLocked(device); Runnable work = updateDisplayStateLocked(device); if (work != null) { Loading @@ -966,11 +976,12 @@ public final class DisplayManagerService extends SystemService { @VisibleForTesting void handleDisplayDeviceChanged(DisplayDevice device) { synchronized (mSyncRoot) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (!mDisplayDevices.contains(device)) { Slog.w(TAG, "Attempted to change non-existent display device: " + info); return; handleDisplayDeviceChangedLocked(device); } } private void handleDisplayDeviceChangedLocked(DisplayDevice device) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); int diff = device.mDebugLastLoggedDeviceInfo.diff(info); if (diff == DisplayDeviceInfo.DIFF_STATE) { Loading Loading @@ -1005,7 +1016,6 @@ public final class DisplayManagerService extends SystemService { scheduleTraversalLocked(false); } } } private void handleDisplayDeviceRemoved(DisplayDevice device) { synchronized (mSyncRoot) { Loading @@ -1014,15 +1024,6 @@ public final class DisplayManagerService extends SystemService { } private void handleDisplayDeviceRemovedLocked(DisplayDevice device) { DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if (!mDisplayDevices.remove(device)) { Slog.w(TAG, "Attempted to remove non-existent display device: " + info); return; } Slog.i(TAG, "Display device removed: " + info); device.mDebugLastLoggedDeviceInfo = info; updateLogicalDisplaysLocked(); scheduleTraversalLocked(false); } Loading @@ -1043,14 +1044,12 @@ public final class DisplayManagerService extends SystemService { } private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) { final int count = mDisplayDevices.size(); for (int i = 0; i < count; i++) { DisplayDevice device = mDisplayDevices.get(i); mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> { Runnable runnable = updateDisplayStateLocked(device); if (runnable != null) { workQueue.add(runnable); } } }); } private Runnable updateDisplayStateLocked(DisplayDevice device) { Loading @@ -1058,6 +1057,8 @@ public final class DisplayManagerService extends SystemService { // by the display power controller (if known). DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { // TODO - multi-display - The rules regarding what display state to apply to each // display will depend on the configuration/mapping of logical displays. return device.requestDisplayStateLocked( mGlobalDisplayState, mGlobalDisplayBrightness); } Loading Loading @@ -1085,7 +1086,7 @@ public final class DisplayManagerService extends SystemService { final int layerStack = assignLayerStackLocked(displayId); LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device); display.updateLocked(mDisplayDevices); display.updateLocked(mDisplayDeviceRepo); if (!display.isValidLocked()) { // This should never happen currently. Slog.w(TAG, "Ignoring display device because the logical display " Loading Loading @@ -1248,7 +1249,7 @@ public final class DisplayManagerService extends SystemService { mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked()); display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo); display.updateLocked(mDisplayDevices); display.updateLocked(mDisplayDeviceRepo); if (!display.isValidLocked()) { mLogicalDisplays.removeAt(i); handleLogicalDisplayRemoved(displayId); Loading Loading @@ -1276,12 +1277,10 @@ public final class DisplayManagerService extends SystemService { clearViewportsLocked(); // Configure each display device. final int count = mDisplayDevices.size(); for (int i = 0; i < count; i++) { DisplayDevice device = mDisplayDevices.get(i); mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> { configureDisplayLocked(t, device); device.performTraversalLocked(t); } }); // Tell the input system about these new viewports. if (mInputManagerInternal != null) { Loading Loading @@ -1714,11 +1713,11 @@ public final class DisplayManagerService extends SystemService { } pw.println(); pw.println("Display Devices: size=" + mDisplayDevices.size()); for (DisplayDevice device : mDisplayDevices) { pw.println("Display Devices: size=" + mDisplayDeviceRepo.sizeLocked()); mDisplayDeviceRepo.forEachLocked(device -> { pw.println(" " + device.getDisplayDeviceInfoLocked()); device.dumpLocked(ipw); } }); final int logicalDisplayCount = mLogicalDisplays.size(); pw.println(); Loading Loading @@ -1864,20 +1863,20 @@ public final class DisplayManagerService extends SystemService { } } private final class DisplayAdapterListener implements DisplayAdapter.Listener { private final class DisplayDeviceListener implements DisplayDeviceRepository.Listener { @Override public void onDisplayDeviceEvent(DisplayDevice device, int event) { public void onDisplayDeviceEventLocked(DisplayDevice device, int event) { switch (event) { case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED: handleDisplayDeviceAdded(device); case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_ADDED: handleDisplayDeviceAddedLocked(device); break; case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED: handleDisplayDeviceChanged(device); case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_CHANGED: handleDisplayDeviceChangedLocked(device); break; case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED: handleDisplayDeviceRemoved(device); case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED: handleDisplayDeviceRemovedLocked(device); break; } } Loading Loading @@ -2573,9 +2572,10 @@ public final class DisplayManagerService extends SystemService { } } }; LogicalDisplay defaultDisplay = mLogicalDisplays.get(Display.DEFAULT_DISPLAY); DisplayDevice defaultDevice = defaultDisplay.getPrimaryDisplayDeviceLocked(); mDisplayPowerController = new DisplayPowerController( mContext, callbacks, handler, sensorManager, blanker, mDisplayDevices.get(Display.DEFAULT_DISPLAY)); mContext, callbacks, handler, sensorManager, blanker, defaultDevice); mSensorManager = sensorManager; } Loading Loading @@ -2689,9 +2689,7 @@ public final class DisplayManagerService extends SystemService { @Override public void onOverlayChanged() { synchronized (mSyncRoot) { for (int i = 0; i < mDisplayDevices.size(); i++) { mDisplayDevices.get(i).onOverlayChangedLocked(); } mDisplayDeviceRepo.forEachLocked(DisplayDevice::onOverlayChangedLocked); } } Loading
services/core/java/com/android/server/display/LogicalDisplay.java +3 −4 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import com.android.server.wm.utils.InsetUtils; import java.io.PrintWriter; import java.util.Arrays; import java.util.List; import java.util.Objects; /** Loading Loading @@ -220,16 +219,16 @@ final class LogicalDisplay { * The logical display might become invalid if it is attached to a display device * that no longer exists. * * @param devices The list of all connected display devices. * @param deviceRepo Repository of active {@link DisplayDevice}s. */ public void updateLocked(List<DisplayDevice> devices) { public void updateLocked(DisplayDeviceRepository deviceRepo) { // Nothing to update if already invalid. if (mPrimaryDisplayDevice == null) { return; } // Check whether logical display has become invalid. if (!devices.contains(mPrimaryDisplayDevice)) { if (!deviceRepo.containsLocked(mPrimaryDisplayDevice)) { mPrimaryDisplayDevice = null; return; } Loading
services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -309,7 +309,8 @@ public class DisplayManagerServiceTest { zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect); displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY; displayDevice.setDisplayDeviceInfo(displayDeviceInfo); displayManager.handleDisplayDeviceAdded(displayDevice); displayManager.getDisplayDeviceRepository() .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); // Find the display id of the added FakeDisplayDevice DisplayManagerService.BinderService bs = displayManager.new BinderService(); Loading
services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java +10 −5 Original line number Diff line number Diff line Loading @@ -28,8 +28,6 @@ import android.view.SurfaceControl; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; public class LogicalDisplayTest { private static final int DISPLAY_ID = 0; private static final int LAYER_STACK = 0; Loading @@ -51,9 +49,16 @@ public class LogicalDisplayTest { mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice); when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(displayDeviceInfo); ArrayList<DisplayDevice> displayDevices = new ArrayList<>(); displayDevices.add(mDisplayDevice); mLogicalDisplay.updateLocked(displayDevices); DisplayDeviceRepository repo = new DisplayDeviceRepository( new DisplayManagerService.SyncRoot(), new DisplayDeviceRepository.Listener() { @Override public void onDisplayDeviceEventLocked(DisplayDevice device, int event) {} @Override public void onTraversalRequested() {} }); repo.onDisplayDeviceEvent(mDisplayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); mLogicalDisplay.updateLocked(repo); } @Test Loading