Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2fb51ba0 authored by Marin Shalamanov's avatar Marin Shalamanov
Browse files

LocalDisplayAdapter test for stale DesiredDisplayConfigSpecs

Test: atest LocalDisplayAdapterTest
Bug: 167966667
Change-Id: I74031943800baac478861f7bbf63f8d3c43582e9
parent da438a1d
Loading
Loading
Loading
Loading
+33 −8
Original line number Diff line number Diff line
@@ -69,21 +69,27 @@ final class LocalDisplayAdapter extends DisplayAdapter {

    private final LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>();

    @SuppressWarnings("unused")  // Becomes active at instantiation time.
    private PhysicalDisplayEventReceiver mPhysicalDisplayEventReceiver;
    private final Injector mInjector;


    // Called with SyncRoot lock held.
    public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
            Context context, Handler handler, Listener listener) {
        this(syncRoot, context, handler, listener, new Injector());
    }

    LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
            Context context, Handler handler, Listener listener, Injector injector) {
        super(syncRoot, context, handler, listener, TAG);
        mInjector = injector;
    }

    @Override
    public void registerLocked() {
        super.registerLocked();

        mPhysicalDisplayEventReceiver = new PhysicalDisplayEventReceiver(getHandler().getLooper());
        mInjector.setDisplayEventListenerLocked(getHandler().getLooper(),
                new LocalDisplayEventListener());

        for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) {
            tryConnectDisplayLocked(physicalDisplayId);
@@ -1052,12 +1058,33 @@ final class LocalDisplayAdapter extends DisplayAdapter {
        }
    }

    private final class PhysicalDisplayEventReceiver extends DisplayEventReceiver {
        PhysicalDisplayEventReceiver(Looper looper) {
    public static class Injector {
        private ProxyDisplayEventReceiver mReceiver;
        public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) {
            mReceiver = new ProxyDisplayEventReceiver(looper, listener);
        }
    }

    public interface DisplayEventListener {
        void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected);
        void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId);
    }

    public static final class ProxyDisplayEventReceiver extends DisplayEventReceiver {
        private final DisplayEventListener mListener;
        ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) {
            super(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_DISPATCH);
            mListener = listener;
        }
        public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
            mListener.onHotplug(timestampNanos, physicalDisplayId, connected);
        }
        public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
            mListener.onConfigChanged(timestampNanos, physicalDisplayId, configId);
        }
    }

        @Override
    private final class LocalDisplayEventListener implements DisplayEventListener {
        public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
            synchronized (getSyncRoot()) {
                if (connected) {
@@ -1067,8 +1094,6 @@ final class LocalDisplayAdapter extends DisplayAdapter {
                }
            }
        }

        @Override
        public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
            if (DEBUG) {
                Slog.d(TAG, "onConfigChanged("
+69 −6
Original line number Diff line number Diff line
@@ -83,6 +83,8 @@ public class LocalDisplayAdapterTest {

    private LinkedList<DisplayAddress.Physical> mAddresses = new LinkedList<>();

    private Injector mInjector;

    @Before
    public void setUp() throws Exception {
        mMockitoSession = mockitoSession()
@@ -94,8 +96,9 @@ public class LocalDisplayAdapterTest {
        doReturn(mMockedResources).when(mMockedContext).getResources();
        LocalServices.removeServiceForTest(LightsManager.class);
        LocalServices.addService(LightsManager.class, mMockedLightsManager);
        mInjector = new Injector();
        mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler,
                mListener);
                mListener, mInjector);
        spyOn(mAdapter);
        doReturn(mMockedContext).when(mAdapter).getOverlayContext();
    }
@@ -222,7 +225,7 @@ public class LocalDisplayAdapterTest {
        display.configs = configs;
        display.activeConfig = 1;
        setUpDisplay(display);
        mAdapter.registerLocked();
        mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);

        assertThat(SurfaceControl.getActiveConfig(display.token)).isEqualTo(1);
@@ -272,7 +275,7 @@ public class LocalDisplayAdapterTest {
                new int[Display.HdrCapabilities.HDR_TYPE_HDR10_PLUS], 1000, 1000, 0);
        display.hdrCapabilities = changedHdrCapabilities;
        setUpDisplay(display);
        mAdapter.registerLocked();
        mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);

        assertThat(mListener.addedDisplays.size()).isEqualTo(1);
@@ -308,7 +311,7 @@ public class LocalDisplayAdapterTest {
        final int[] changedColorModes = new int[]{Display.COLOR_MODE_DEFAULT};
        display.colorModes = changedColorModes;
        setUpDisplay(display);
        mAdapter.registerLocked();
        mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);

        assertThat(mListener.addedDisplays.size()).isEqualTo(1);
@@ -322,6 +325,35 @@ public class LocalDisplayAdapterTest {
        assertThat(displayDeviceInfo.supportedColorModes).isEqualTo(changedColorModes);
    }

    @Test
    public void testDisplayChange_withStaleDesiredDisplayConfigSpecs() throws Exception {
        SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[]{
                createFakeDisplayConfig(1920, 1080, 60f),
                createFakeDisplayConfig(1920, 1080, 50f)
        };
        final int activeConfig = 0;
        FakeDisplay display = new FakeDisplay(PORT_A, configs, activeConfig);
        display.desiredDisplayConfigSpecs.defaultConfig = 1;

        setUpDisplay(display);
        updateAvailableDisplays();
        mAdapter.registerLocked();
        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);

        // Change the display
        display.configs = new SurfaceControl.DisplayConfig[]{
                createFakeDisplayConfig(1920, 1080, 60f)
        };
        // SurfaceFlinger can return a stale defaultConfig. Make sure this doesn't
        // trigger ArrayOutOfBoundsException.
        display.desiredDisplayConfigSpecs.defaultConfig = 1;

        setUpDisplay(display);
        updateAvailableDisplays();
        mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
    }

    private void assertDisplayDpi(DisplayDeviceInfo info, int expectedPort,
                                  float expectedXdpi,
                                  float expectedYDpi,
@@ -356,6 +388,8 @@ public class LocalDisplayAdapterTest {
        public int[] colorModes = new int[]{ Display.COLOR_MODE_DEFAULT };
        public Display.HdrCapabilities hdrCapabilities = new Display.HdrCapabilities(new int[0],
                1000, 1000, 0);
        public SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs =
                new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f, 60.f, 60.f);

        private FakeDisplay(int port) {
            this.address = createDisplayAddress(port);
@@ -387,7 +421,7 @@ public class LocalDisplayAdapterTest {
                () -> SurfaceControl.getDisplayColorModes(display.token));
        doReturn(display.hdrCapabilities).when(
                () -> SurfaceControl.getHdrCapabilities(display.token));
        doReturn(new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f, 60.f, 60.f))
        doReturn(display.desiredDisplayConfigSpecs)
                .when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token));
    }

@@ -422,7 +456,7 @@ public class LocalDisplayAdapterTest {
        return config;
    }

    private void waitForHandlerToComplete(Handler handler, long waitTimeMs)
    private static void waitForHandlerToComplete(Handler handler, long waitTimeMs)
            throws InterruptedException {
        final Object lock = new Object();
        synchronized (lock) {
@@ -435,6 +469,35 @@ public class LocalDisplayAdapterTest {
        }
    }

    private class HotplugTransmitter {
        private final Handler mHandler;
        private final LocalDisplayAdapter.DisplayEventListener mListener;

        HotplugTransmitter(Looper looper, LocalDisplayAdapter.DisplayEventListener listener) {
            mHandler = new Handler(looper);
            mListener = listener;
        }

        public void sendHotplug(FakeDisplay display, boolean connected)
                throws InterruptedException {
            mHandler.post(() -> mListener.onHotplug(/* timestampNanos = */ 0,
                    display.address.getPhysicalDisplayId(), connected));
            waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
        }
    }

    private class Injector extends LocalDisplayAdapter.Injector {
        private HotplugTransmitter mTransmitter;
        @Override
        public void setDisplayEventListenerLocked(Looper looper,
                LocalDisplayAdapter.DisplayEventListener listener) {
            mTransmitter = new HotplugTransmitter(looper, listener);
        }
        public HotplugTransmitter getTransmitter() {
            return mTransmitter;
        }
    }

    private class TestListener implements DisplayAdapter.Listener {
        public ArrayList<DisplayDevice> addedDisplays = new ArrayList<>();
        public ArrayList<DisplayDevice> changedDisplays = new ArrayList<>();