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

Commit 05f9398f authored by Marin Shalamanov's avatar Marin Shalamanov
Browse files

SF: Refactor HWComposer::onHotplug()

Currently HWComposer::onHotplug() contains logic that is
executed when hotplug disconnect or connect event occurs.
However reading what exactly is done during e.g. hotplug
connect is hard, because the logic is spread between two
if statements and the function HWComposer::onHotplugConnect().
This change moves all hotplug connect logic to
HWComposer::onHotplugConnect() and all disconnect logic
to a new function HWComposer::onHotplugDisconnect().

Additionally this CLs refactors onHotplugConnect() which
is currently responsible for multiple concerns, which is
making the code hard to understand and reuse.

 - checking if the event should be ignored is moved to
   a new function shouldIgnoreHotplugConnect()
 - creating the necessary state for the new display is
   moved to a new function allocatePhysicalDisplay()

Some of the newly created functions will be directly reused
in following CLs.

Bug: 143451809
Test: m surfaceflinger
Test: atest libsurfaceflinger_unittest
Change-Id: Ib4dae2ce81e8cac176a56b6de787a4f76d01c050
parent 1581d90e
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -45,6 +45,7 @@ public:


    MOCK_METHOD3(allocateVirtualDisplay,
    MOCK_METHOD3(allocateVirtualDisplay,
                 std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
                 std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
    MOCK_METHOD2(allocatePhysicalDisplay, void(hwc2_display_t, DisplayId));
    MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
    MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
    MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
    MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
    MOCK_METHOD3(getDeviceCompositionChanges,
    MOCK_METHOD3(getDeviceCompositionChanges,
+94 −79
Original line number Original line Diff line number Diff line
@@ -205,56 +205,14 @@ bool HWComposer::hasDisplayCapability(const std::optional<DisplayId>& displayId,


std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
                                                               HWC2::Connection connection) {
                                                               HWC2::Connection connection) {
    std::optional<DisplayIdentificationInfo> info;
    switch (connection) {

        case HWC2::Connection::Connected:
    if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) {
            return onHotplugConnect(hwcDisplayId);
        info = DisplayIdentificationInfo{.id = *displayId,
        case HWC2::Connection::Disconnected:
                                         .name = std::string(),
            return onHotplugDisconnect(hwcDisplayId);
                                         .deviceProductInfo = std::nullopt};
        case HWC2::Connection::Invalid:
    } else {
        if (connection == HWC2::Connection::Disconnected) {
            ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId);
            return {};
            return {};
    }
    }

        info = onHotplugConnect(hwcDisplayId);
        if (!info) return {};
    }

    ALOGV("%s: %s %s display %s with HWC ID %" PRIu64, __FUNCTION__, to_string(connection).c_str(),
          hwcDisplayId == mInternalHwcDisplayId ? "internal" : "external",
          to_string(info->id).c_str(), hwcDisplayId);

    if (connection == HWC2::Connection::Connected) {
        auto& displayData = mDisplayData[info->id];
        // If we get a hotplug connected event for a display we already have,
        // destroy the display and recreate it. This will force us to requery
        // the display params and recreate all layers on that display.
        if (displayData.hwcDisplay != nullptr && displayData.hwcDisplay->isConnected()) {
            ALOGI("Hotplug connecting an already connected display."
                  " Clearing old display state.");
        }
        displayData.hwcDisplay.reset();
        auto newDisplay =
                std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities, hwcDisplayId,
                                                      HWC2::DisplayType::Physical);
        newDisplay->setConnected(true);
        displayData.hwcDisplay = std::move(newDisplay);
        mPhysicalDisplayIdMap[hwcDisplayId] = info->id;
    } else if (connection == HWC2::Connection::Disconnected) {
        // The display will later be destroyed by a call to
        // destroyDisplay(). For now we just mark it disconnected.
        auto& displayData = mDisplayData[info->id];
        if (displayData.hwcDisplay) {
            displayData.hwcDisplay->setConnected(false);
        } else {
            ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId);
        }
        // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay
        // via SurfaceFlinger's onHotplugReceived callback handling
    }

    return info;
}
}


bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp) {
bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp) {
@@ -337,6 +295,22 @@ std::optional<DisplayId> HWComposer::allocateVirtualDisplay(uint32_t width, uint
    return displayId;
    return displayId;
}
}


void HWComposer::allocatePhysicalDisplay(hwc2_display_t hwcDisplayId, DisplayId displayId) {
    if (!mInternalHwcDisplayId) {
        mInternalHwcDisplayId = hwcDisplayId;
    } else if (mInternalHwcDisplayId != hwcDisplayId && !mExternalHwcDisplayId) {
        mExternalHwcDisplayId = hwcDisplayId;
    }

    auto& displayData = mDisplayData[displayId];
    auto newDisplay =
            std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities, hwcDisplayId,
                                                  HWC2::DisplayType::Physical);
    newDisplay->setConnected(true);
    displayData.hwcDisplay = std::move(newDisplay);
    mPhysicalDisplayIdMap[hwcDisplayId] = displayId;
}

HWC2::Layer* HWComposer::createLayer(DisplayId displayId) {
HWC2::Layer* HWComposer::createLayer(DisplayId displayId) {
    RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
    RETURN_IF_INVALID_DISPLAY(displayId, nullptr);


@@ -911,52 +885,93 @@ std::optional<hwc2_display_t> HWComposer::fromPhysicalDisplayId(DisplayId displa
    return {};
    return {};
}
}


std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) {
bool HWComposer::shouldIgnoreHotplugConnect(hwc2_display_t hwcDisplayId,
                                            bool hasDisplayIdentificationData) const {
    if (isUsingVrComposer() && mInternalHwcDisplayId) {
    if (isUsingVrComposer() && mInternalHwcDisplayId) {
        ALOGE("Ignoring connection of external display %" PRIu64 " in VR mode", hwcDisplayId);
        ALOGE("Ignoring connection of external display %" PRIu64 " in VR mode", hwcDisplayId);
        return {};
        return true;
    }
    }


    if (mHasMultiDisplaySupport && !hasDisplayIdentificationData) {
        ALOGE("Ignoring connection of display %" PRIu64 " without identification data",
              hwcDisplayId);
        return true;
    }

    if (!mHasMultiDisplaySupport && mInternalHwcDisplayId && mExternalHwcDisplayId) {
        ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId);
        return true;
    }

    return false;
}

std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) {
    std::optional<DisplayIdentificationInfo> info;
    if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) {
        info = DisplayIdentificationInfo{.id = *displayId,
                                         .name = std::string(),
                                         .deviceProductInfo = std::nullopt};
    } else {
        uint8_t port;
        uint8_t port;
        DisplayIdentificationData data;
        DisplayIdentificationData data;
    const bool hasMultiDisplaySupport = getDisplayIdentificationData(hwcDisplayId, &port, &data);
        const bool hasDisplayIdentificationData =

                getDisplayIdentificationData(hwcDisplayId, &port, &data);
        if (mPhysicalDisplayIdMap.empty()) {
        if (mPhysicalDisplayIdMap.empty()) {
        mHasMultiDisplaySupport = hasMultiDisplaySupport;
            mHasMultiDisplaySupport = hasDisplayIdentificationData;
            ALOGI("Switching to %s multi-display mode",
            ALOGI("Switching to %s multi-display mode",
              hasMultiDisplaySupport ? "generalized" : "legacy");
                  mHasMultiDisplaySupport ? "generalized" : "legacy");
    } else if (mHasMultiDisplaySupport && !hasMultiDisplaySupport) {
        ALOGE("Ignoring connection of display %" PRIu64 " without identification data",
              hwcDisplayId);
        return {};
        }
        }


    std::optional<DisplayIdentificationInfo> info;
        if (shouldIgnoreHotplugConnect(hwcDisplayId, hasDisplayIdentificationData)) {
            return {};
        }


        info = [this, hwcDisplayId, &port, &data, hasDisplayIdentificationData] {
            const bool isPrimary = !mInternalHwcDisplayId;
            if (mHasMultiDisplaySupport) {
            if (mHasMultiDisplaySupport) {
        info = parseDisplayIdentificationData(port, data);
                if (const auto info = parseDisplayIdentificationData(port, data)) {
        ALOGE_IF(!info, "Failed to parse identification data for display %" PRIu64, hwcDisplayId);
                    return *info;
    } else if (mInternalHwcDisplayId && mExternalHwcDisplayId) {
                }
        ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId);
                ALOGE("Failed to parse identification data for display %" PRIu64, hwcDisplayId);
        return {};
            } else {
            } else {
        ALOGW_IF(hasMultiDisplaySupport, "Ignoring identification data for display %" PRIu64,
                ALOGW_IF(hasDisplayIdentificationData,
                 hwcDisplayId);
                         "Ignoring identification data for display %" PRIu64, hwcDisplayId);
        port = mInternalHwcDisplayId ? HWC_DISPLAY_EXTERNAL : HWC_DISPLAY_PRIMARY;
                port = isPrimary ? HWC_DISPLAY_PRIMARY : HWC_DISPLAY_EXTERNAL;
            }
            }


    if (!mInternalHwcDisplayId) {
            return DisplayIdentificationInfo{.id = getFallbackDisplayId(port),
        mInternalHwcDisplayId = hwcDisplayId;
                                             .name = isPrimary ? "Internal display"
    } else if (!mExternalHwcDisplayId) {
                                                               : "External display",
        mExternalHwcDisplayId = hwcDisplayId;
                                             .deviceProductInfo = std::nullopt};
        }();
    }
    }


    if (info) return info;
    if (!isConnected(info->id)) {
        allocatePhysicalDisplay(hwcDisplayId, info->id);
    }
    return info;
}


    return DisplayIdentificationInfo{.id = getFallbackDisplayId(port),
std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect(
                                     .name = hwcDisplayId == mInternalHwcDisplayId
        hwc2_display_t hwcDisplayId) {
                                             ? "Internal display"
    const auto displayId = toPhysicalDisplayId(hwcDisplayId);
                                             : "External display",
    if (!displayId) {
        ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId);
        return {};
    }

    // The display will later be destroyed by a call to
    // destroyDisplay(). For now we just mark it disconnected.
    if (isConnected(*displayId)) {
        mDisplayData[*displayId].hwcDisplay->setConnected(false);
    } else {
        ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId);
    }
    // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay
    // via SurfaceFlinger's onHotplugReceived callback handling
    return DisplayIdentificationInfo{.id = *displayId,
                                     .name = std::string(),
                                     .deviceProductInfo = std::nullopt};
                                     .deviceProductInfo = std::nullopt};
}
}


+10 −0
Original line number Original line Diff line number Diff line
@@ -77,6 +77,8 @@ public:
    virtual std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
    virtual std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
                                                            ui::PixelFormat* format) = 0;
                                                            ui::PixelFormat* format) = 0;


    virtual void allocatePhysicalDisplay(hwc2_display_t hwcDisplayId, DisplayId displayId) = 0;

    // Attempts to create a new layer on this display
    // Attempts to create a new layer on this display
    virtual HWC2::Layer* createLayer(DisplayId displayId) = 0;
    virtual HWC2::Layer* createLayer(DisplayId displayId) = 0;
    // Destroy a previously created layer
    // Destroy a previously created layer
@@ -164,6 +166,7 @@ public:


    // Returns stable display ID (and display name on connection of new or previously disconnected
    // Returns stable display ID (and display name on connection of new or previously disconnected
    // display), or std::nullopt if hotplug event was ignored.
    // display), or std::nullopt if hotplug event was ignored.
    // This function is called from SurfaceFlinger.
    virtual std::optional<DisplayIdentificationInfo> onHotplug(hwc2_display_t hwcDisplayId,
    virtual std::optional<DisplayIdentificationInfo> onHotplug(hwc2_display_t hwcDisplayId,
                                                               HWC2::Connection connection) = 0;
                                                               HWC2::Connection connection) = 0;


@@ -238,6 +241,9 @@ public:
    std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
    std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
                                                    ui::PixelFormat* format) override;
                                                    ui::PixelFormat* format) override;


    // Called from SurfaceFlinger, when the state for a new physical display needs to be recreated.
    void allocatePhysicalDisplay(hwc2_display_t hwcDisplayId, DisplayId displayId) override;

    // Attempts to create a new layer on this display
    // Attempts to create a new layer on this display
    HWC2::Layer* createLayer(DisplayId displayId) override;
    HWC2::Layer* createLayer(DisplayId displayId) override;
    // Destroy a previously created layer
    // Destroy a previously created layer
@@ -361,6 +367,10 @@ private:
    friend TestableSurfaceFlinger;
    friend TestableSurfaceFlinger;


    std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
    std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
    std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hwc2_display_t hwcDisplayId);
    bool shouldIgnoreHotplugConnect(hwc2_display_t hwcDisplayId,
                                    bool hasDisplayIdentificationData) const;

    void loadCapabilities();
    void loadCapabilities();
    void loadLayerMetadataSupport();
    void loadLayerMetadataSupport();
    uint32_t getMaxVirtualDisplayCount() const;
    uint32_t getMaxVirtualDisplayCount() const;