Determine displayType in SurfaceFlinger

This change eliminates an assumption that the first hotplug connect
event is for the primary display, and all other events are for the
external display.

Bug: 38464421
Test: Boots, settings app navigable
Change-Id: I753deb9a4e99a7b225ab89562c7acf4ce284dbf5
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index affe505..070b691 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -52,24 +52,13 @@
 class ComposerCallbackBridge : public Hwc2::IComposerCallback {
 public:
     ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId)
-            : mCallback(callback), mSequenceId(sequenceId),
-              mHasPrimaryDisplay(false) {}
+            : mCallback(callback), mSequenceId(sequenceId) {}
 
     Return<void> onHotplug(Hwc2::Display display,
                            IComposerCallback::Connection conn) override
     {
         HWC2::Connection connection = static_cast<HWC2::Connection>(conn);
-        if (!mHasPrimaryDisplay) {
-            LOG_ALWAYS_FATAL_IF(connection != HWC2::Connection::Connected,
-                    "Initial onHotplug callback should be "
-                    "primary display connected");
-            mHasPrimaryDisplay = true;
-            mCallback->onHotplugReceived(mSequenceId, display,
-                                         connection, true);
-        } else {
-            mCallback->onHotplugReceived(mSequenceId, display,
-                                         connection, false);
-        }
+        mCallback->onHotplugReceived(mSequenceId, display, connection);
         return Void();
     }
 
@@ -85,12 +74,9 @@
         return Void();
     }
 
-    bool HasPrimaryDisplay() { return mHasPrimaryDisplay; }
-
 private:
     ComposerCallback* mCallback;
     int32_t mSequenceId;
-    bool mHasPrimaryDisplay;
 };
 
 } // namespace anonymous
@@ -117,8 +103,6 @@
     sp<ComposerCallbackBridge> callbackBridge(
             new ComposerCallbackBridge(callback, sequenceId));
     mComposer->registerCallback(callbackBridge);
-    LOG_ALWAYS_FATAL_IF(!callbackBridge->HasPrimaryDisplay(),
-            "Registered composer callback but didn't get primary display");
 }
 
 // Required by HWC2 device
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index a15c6d9..7b98b3e 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -65,8 +65,7 @@
 class ComposerCallback {
  public:
     virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
-                                   Connection connection,
-                                   bool primaryDisplay) = 0;
+                                   Connection connection) = 0;
     virtual void onRefreshReceived(int32_t sequenceId,
                                    hwc2_display_t display) = 0;
     virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c0f8f96..1677b07 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -119,23 +119,22 @@
     }
 }
 
-void HWComposer::onHotplug(hwc2_display_t displayId,
+void HWComposer::onHotplug(hwc2_display_t displayId, int32_t displayType,
                            HWC2::Connection connection) {
-    ALOGV("hotplug: %" PRIu64 ", %s", displayId,
+    if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+        ALOGE("Invalid display type of %d", displayType);
+        return;
+    }
+
+    ALOGV("hotplug: %" PRIu64 ", %s %s", displayId,
+            displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
             to_string(connection).c_str());
     mHwcDevice->onHotplug(displayId, connection);
-    if (!mDisplayData[0].hwcDisplay) {
-        ALOGE_IF(connection != HWC2::Connection::Connected, "Assumed primary"
-                " display would be connected");
-        mDisplayData[0].hwcDisplay = mHwcDevice->getDisplayById(displayId);
-        mHwcDisplaySlots[displayId] = 0;
-    } else {
-        // Disconnect is handled through HWComposer::disconnectDisplay via
-        // SurfaceFlinger's onHotplugReceived callback handling
-        if (connection == HWC2::Connection::Connected) {
-            mDisplayData[1].hwcDisplay = mHwcDevice->getDisplayById(displayId);
-            mHwcDisplaySlots[displayId] = 1;
-        }
+    // Disconnect is handled through HWComposer::disconnectDisplay via
+    // SurfaceFlinger's onHotplugReceived callback handling
+    if (connection == HWC2::Connection::Connected) {
+        mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(displayId);
+        mHwcDisplaySlots[displayId] = displayType;
     }
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 74b3a38..ee0a725 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -136,7 +136,7 @@
     // DisplayDevice::DisplayType of the display is returned as an output param.
     bool onVsync(hwc2_display_t displayId, int64_t timestamp,
                  int32_t* outDisplay);
-    void onHotplug(hwc2_display_t displayId, HWC2::Connection connection);
+    void onHotplug(hwc2_display_t displayId, int32_t displayType, HWC2::Connection connection);
 
     void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 707a0de..3145ac3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1263,14 +1263,10 @@
     *compositorTiming = getBE().mCompositorTiming;
 }
 
-void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
-        hwc2_display_t display, HWC2::Connection connection,
-        bool primaryDisplay) {
-    ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)",
-          sequenceId, display,
-          connection == HWC2::Connection::Connected ?
-                  "connected" : "disconnected",
-          primaryDisplay ? "primary" : "external");
+void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+                                       HWC2::Connection connection) {
+    ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s)", sequenceId, display,
+          connection == HWC2::Connection::Connected ? "connected" : "disconnected");
 
     // Ignore events that do not have the right sequenceId.
     if (sequenceId != getBE().mComposerSequenceId) {
@@ -1283,7 +1279,7 @@
     // acquire it here.
     ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
 
-    mPendingHotplugEvents.emplace_back(HotplugEvent{display, connection, primaryDisplay});
+    mPendingHotplugEvents.emplace_back(HotplugEvent{display, connection});
 
     setTransactionFlags(eDisplayTransactionNeeded);
 }
@@ -2044,17 +2040,46 @@
     // here the transaction has been committed
 }
 
+DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t display,
+        HWC2::Connection connection) const {
+    // Figure out whether the event is for the primary display or an
+    // external display by matching the Hwc display id against one for a
+    // connected display. If we did not find a match, we then check what
+    // displays are not already connected to determine the type. If we don't
+    // have a connected primary display, we assume the new display is meant to
+    // be the primary display, and then if we don't have an external display,
+    // we assume it is that.
+    const auto primaryDisplayId =
+            getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
+    const auto externalDisplayId =
+            getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_EXTERNAL);
+    if (primaryDisplayId && primaryDisplayId == display) {
+        return DisplayDevice::DISPLAY_PRIMARY;
+    } else if (externalDisplayId && externalDisplayId == display) {
+        return  DisplayDevice::DISPLAY_EXTERNAL;
+    } else if (connection == HWC2::Connection::Connected && !primaryDisplayId) {
+        return DisplayDevice::DISPLAY_PRIMARY;
+    } else if (connection == HWC2::Connection::Connected && !externalDisplayId) {
+        return DisplayDevice::DISPLAY_EXTERNAL;
+    }
+
+    return DisplayDevice::DISPLAY_ID_INVALID;
+}
+
 void SurfaceFlinger::processDisplayHotplugEventsLocked() {
     for (const auto& event : mPendingHotplugEvents) {
-        DisplayDevice::DisplayType displayType = event.isPrimaryDisplay ?
-                DisplayDevice::DISPLAY_PRIMARY : DisplayDevice::DISPLAY_EXTERNAL;
+        auto displayType = determineDisplayType(event.display, event.connection);
+        if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
+            ALOGW("Unable to determine the display type for display %" PRIu64, event.display);
+            continue;
+        }
 
         if (getBE().mHwc->isUsingVrComposer() && displayType == DisplayDevice::DISPLAY_EXTERNAL) {
             ALOGE("External displays are not supported by the vr hardware composer.");
             continue;
         }
 
-        getBE().mHwc->onHotplug(event.display, event.connection);
+        getBE().mHwc->onHotplug(event.display, displayType, event.connection);
 
         if (event.connection == HWC2::Connection::Connected) {
             ALOGV("Creating built in display %d", displayType);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 921bb45..a18be9b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -417,8 +417,7 @@
     void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
                          int64_t timestamp) override;
     void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
-                           HWC2::Connection connection,
-                           bool primaryDisplay) override;
+                           HWC2::Connection connection) override;
     void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override;
 
     /* ------------------------------------------------------------------------
@@ -631,6 +630,8 @@
     /* ------------------------------------------------------------------------
      * Display management
      */
+    DisplayDevice::DisplayType determineDisplayType(hwc2_display_t display,
+            HWC2::Connection connection) const;
     void processDisplayChangesLocked();
     void processDisplayHotplugEventsLocked();
 
@@ -737,7 +738,6 @@
     struct HotplugEvent {
         hwc2_display_t display;
         HWC2::Connection connection = HWC2::Connection::Invalid;
-        bool isPrimaryDisplay;
     };
     // protected by mStateLock
     std::vector<HotplugEvent> mPendingHotplugEvents;