SF: Propagate display hotplug errors

Add support for SurfaceFlinger to handle display connection
errors and propagate any error code on hotplug event up the
stack.

Bug: 241286153
Test: manual
Change-Id: I88afeb4f61b13714a81138180db0762cf3ae4ab0
diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp
index 46fb068..93df124 100644
--- a/libs/gui/Choreographer.cpp
+++ b/libs/gui/Choreographer.cpp
@@ -324,6 +324,12 @@
           to_string(displayId).c_str(), toString(connected));
 }
 
+void Choreographer::dispatchHotplugConnectionError(nsecs_t, int32_t connectionError) {
+    ALOGV("choreographer %p ~ received hotplug connection error event (connectionError=%d), "
+          "ignoring.",
+          this, connectionError);
+}
+
 void Choreographer::dispatchModeChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) {
     LOG_ALWAYS_FATAL("dispatchModeChanged was called but was never registered");
 }
@@ -394,4 +400,4 @@
     return iter->second;
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 8a88377..5dd058c 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -173,7 +173,13 @@
                     *outVsyncEventData = ev.vsync.vsyncData;
                     break;
                 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
-                    dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
+                    if (ev.hotplug.connectionError == 0) {
+                        dispatchHotplug(ev.header.timestamp, ev.header.displayId,
+                                        ev.hotplug.connected);
+                    } else {
+                        dispatchHotplugConnectionError(ev.header.timestamp,
+                                                       ev.hotplug.connectionError);
+                    }
                     break;
                 case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
                     dispatchModeChanged(ev.header.timestamp, ev.header.displayId,
diff --git a/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp b/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
index 6e4f074..0d2a52b 100644
--- a/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
+++ b/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
@@ -62,7 +62,10 @@
 
         }
         case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: {
-            event.hotplug = DisplayEventReceiver::Event::Hotplug{fdp->ConsumeBool() /*connected*/};
+            event.hotplug =
+                    DisplayEventReceiver::Event::Hotplug{fdp->ConsumeBool() /*connected*/,
+                                                         fdp->ConsumeIntegral<
+                                                                 int32_t>() /*connectionError*/};
             break;
         }
         case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
index 177d5f8..bdf8856 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -197,6 +197,7 @@
 
     MOCK_METHOD4(dispatchVsync, void(nsecs_t, PhysicalDisplayId, uint32_t, VsyncEventData));
     MOCK_METHOD3(dispatchHotplug, void(nsecs_t, PhysicalDisplayId, bool));
+    MOCK_METHOD2(dispatchHotplugConnectionError, void(nsecs_t, int32_t));
     MOCK_METHOD4(dispatchModeChanged, void(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t));
     MOCK_METHOD2(dispatchNullEvent, void(nsecs_t, PhysicalDisplayId));
     MOCK_METHOD3(dispatchFrameRateOverrides,
diff --git a/libs/gui/include/gui/Choreographer.h b/libs/gui/include/gui/Choreographer.h
index 1df9b11..9fef512 100644
--- a/libs/gui/include/gui/Choreographer.h
+++ b/libs/gui/include/gui/Choreographer.h
@@ -110,6 +110,7 @@
     void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
                        VsyncEventData vsyncEventData) override;
     void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
+    void dispatchHotplugConnectionError(nsecs_t timestamp, int32_t connectionError) override;
     void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
                              nsecs_t vsyncPeriod) override;
     void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override;
@@ -137,4 +138,4 @@
     static constexpr size_t kMaxStartTimes = 250;
 };
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 140efa6..fe2dd20 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -53,6 +53,9 @@
                                VsyncEventData vsyncEventData) = 0;
     virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
                                  bool connected) = 0;
+
+    virtual void dispatchHotplugConnectionError(nsecs_t timestamp, int32_t connectionError) = 0;
+
     virtual void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
                                      nsecs_t vsyncPeriod) = 0;
     // AChoreographer-specific hook for processing null-events so that looper
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 7fd6c35..79582ce 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -88,6 +88,7 @@
 
         struct Hotplug {
             bool connected;
+            int32_t connectionError __attribute__((aligned(4)));
         };
 
         struct ModeChange {
diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp
index 3949d70..29eeaa8 100644
--- a/libs/gui/tests/DisplayEventStructLayout_test.cpp
+++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp
@@ -59,6 +59,7 @@
                  lastFrameTimelineOffset + 16);
 
     CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0);
+    CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connectionError, 4);
 
     CHECK_OFFSET(DisplayEventReceiver::Event::ModeChange, modeId, 0);
     CHECK_OFFSET(DisplayEventReceiver::Event::ModeChange, vsyncPeriod, 8);