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

Commit 8c258204 authored by Marin Shalamanov's avatar Marin Shalamanov Committed by Android (Google) Code Review
Browse files

Merge changes I89996d93,Ib4dae2ce

* changes:
  SF: Update display properties on hotplug connect
  SF: Refactor HWComposer::onHotplug()
parents c730aff3 700e639f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ public:

    MOCK_METHOD3(allocateVirtualDisplay,
                 std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
    MOCK_METHOD2(allocatePhysicalDisplay, void(hwc2_display_t, DisplayId));
    MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
    MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
    MOCK_METHOD3(getDeviceCompositionChanges,
+2 −1
Original line number Diff line number Diff line
@@ -183,9 +183,10 @@ struct DisplayDeviceState {
    struct Physical {
        DisplayId id;
        DisplayConnectionType type;
        hwc2_display_t hwcDisplayId;

        bool operator==(const Physical& other) const {
            return id == other.id && type == other.type;
            return id == other.id && type == other.type && hwcDisplayId == other.hwcDisplayId;
        }
    };

+94 −79
Original line number 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,
                                                               HWC2::Connection connection) {
    std::optional<DisplayIdentificationInfo> info;

    if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) {
        info = DisplayIdentificationInfo{.id = *displayId,
                                         .name = std::string(),
                                         .deviceProductInfo = std::nullopt};
    } else {
        if (connection == HWC2::Connection::Disconnected) {
            ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId);
    switch (connection) {
        case HWC2::Connection::Connected:
            return onHotplugConnect(hwcDisplayId);
        case HWC2::Connection::Disconnected:
            return onHotplugDisconnect(hwcDisplayId);
        case HWC2::Connection::Invalid:
            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) {
@@ -337,6 +295,22 @@ std::optional<DisplayId> HWComposer::allocateVirtualDisplay(uint32_t width, uint
    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) {
    RETURN_IF_INVALID_DISPLAY(displayId, nullptr);

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

std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) {
bool HWComposer::shouldIgnoreHotplugConnect(hwc2_display_t hwcDisplayId,
                                            bool hasDisplayIdentificationData) const {
    if (isUsingVrComposer() && mInternalHwcDisplayId) {
        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;
        DisplayIdentificationData data;
    const bool hasMultiDisplaySupport = getDisplayIdentificationData(hwcDisplayId, &port, &data);

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

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

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

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

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

    return DisplayIdentificationInfo{.id = getFallbackDisplayId(port),
                                     .name = hwcDisplayId == mInternalHwcDisplayId
                                             ? "Internal display"
                                             : "External display",
std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect(
        hwc2_display_t hwcDisplayId) {
    const auto displayId = toPhysicalDisplayId(hwcDisplayId);
    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};
}

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

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

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

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

@@ -238,6 +241,9 @@ public:
    std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
                                                    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
    HWC2::Layer* createLayer(DisplayId displayId) override;
    // Destroy a previously created layer
@@ -361,6 +367,10 @@ private:
    friend TestableSurfaceFlinger;

    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 loadLayerMetadataSupport();
    uint32_t getMaxVirtualDisplayCount() const;
+26 −16
Original line number Diff line number Diff line
@@ -2389,7 +2389,8 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {
                }

                DisplayDeviceState state;
                state.physical = {displayId, getHwComposer().getDisplayConnectionType(displayId)};
                state.physical = {displayId, getHwComposer().getDisplayConnectionType(displayId),
                                  event.hwcDisplayId};
                state.isSecure = true; // All physical displays are currently considered secure.
                state.displayName = info->name;

@@ -2398,6 +2399,12 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {
                mPhysicalDisplayTokens.emplace(displayId, std::move(token));

                mInterceptor->saveDisplayCreation(state);
            } else {
                ALOGV("Recreating display %s", to_string(displayId).c_str());

                const auto token = it->second;
                auto& state = mCurrentState.displays.editValueFor(token);
                state.sequenceId = DisplayDeviceState{}.sequenceId;
            }
        } else {
            ALOGV("Removing display %s", to_string(displayId).c_str());
@@ -2575,20 +2582,17 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
        producer = bqProducer;
    }

    if (displaySurface != nullptr) {
        mDisplays.emplace(displayToken,
                          setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
                                                        displaySurface, producer));
    LOG_FATAL_IF(!displaySurface);
    const auto display = setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
                                                       displaySurface, producer);
    mDisplays.emplace(displayToken, display);
    if (!state.isVirtual()) {
            LOG_ALWAYS_FATAL_IF(!displayId);
        LOG_FATAL_IF(!displayId);
        dispatchDisplayHotplugEvent(displayId->value, true);
    }

        const auto displayDevice = mDisplays[displayToken];
        if (displayDevice->isPrimary()) {
            mScheduler->onPrimaryDisplayAreaChanged(displayDevice->getWidth() *
                                                    displayDevice->getHeight());
        }
    if (display->isPrimary()) {
        mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight());
    }
}

@@ -2599,7 +2603,7 @@ void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
        display->disconnect();

        if (!display->isVirtual()) {
            LOG_ALWAYS_FATAL_IF(!displayId);
            LOG_FATAL_IF(!displayId);
            dispatchDisplayHotplugEvent(displayId->value, false);
        }
    }
@@ -2612,13 +2616,19 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
                                           const DisplayDeviceState& drawingState) {
    const sp<IBinder> currentBinder = IInterface::asBinder(currentState.surface);
    const sp<IBinder> drawingBinder = IInterface::asBinder(drawingState.surface);
    if (currentBinder != drawingBinder) {
    if (currentBinder != drawingBinder || currentState.sequenceId != drawingState.sequenceId) {
        // changing the surface is like destroying and recreating the DisplayDevice
        if (const auto display = getDisplayDeviceLocked(displayToken)) {
            display->disconnect();
        }
        mDisplays.erase(displayToken);
        if (const auto& physical = currentState.physical) {
            getHwComposer().allocatePhysicalDisplay(physical->hwcDisplayId, physical->id);
        }
        processDisplayAdded(displayToken, currentState);
        if (currentState.physical) {
            initializeDisplays();
        }
        return;
    }

Loading