SF: Tie VSyncState lifetime to display hotplug

This CL creates/destroys EventThread::VSyncState when the display is
connected/disconnected.

Bug: 74619554
Test: libsurfaceflinger_unittest
Test: dumpsys SurfaceFlinger --vsync
Change-Id: I46dad4857222b6d2932ab568c4d66325edc3371b
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index e6cdd02..79fb034 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -104,6 +104,10 @@
 
     createThread();
     mConnection = createConnection(mConnectionEventCallRecorder);
+
+    // A display must be connected for VSYNC events to be delivered.
+    mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
+    expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
 }
 
 EventThreadTest::~EventThreadTest() {
@@ -207,6 +211,23 @@
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
 }
 
+TEST_F(EventThreadTest, vsyncRequestIsIgnoredIfDisplayIsDisconnected) {
+    mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+    expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
+
+    // Signal that we want the next vsync event to be posted to the connection.
+    mThread->requestNextVsync(mConnection, false);
+
+    // EventThread should not enable vsync callbacks.
+    EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+
+    // Use the received callback to signal a vsync event.
+    // The event should not be received by the interceptor nor the connection.
+    mCallback->onVSyncEvent(123);
+    EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall(0us).has_value());
+    EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
+}
+
 TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
     // Signal that we want the next vsync event to be posted to the connection
     mThread->requestNextVsync(mConnection, false);