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

Commit 21e61b02 authored by Dominik Laskowski's avatar Dominik Laskowski Committed by Android (Google) Code Review
Browse files

Merge changes I2b711317,I42e18339

* changes:
  SF: Do not abort on duplicate hotplug disconnect
  SF: Extract processHotplug from configureLocked
parents 86860872 f2ddca6b
Loading
Loading
Loading
Loading
+8 −15
Original line number Diff line number Diff line
@@ -252,11 +252,7 @@ std::shared_ptr<HWC2::Layer> HWComposer::createLayer(HalDisplayId displayId) {
}

bool HWComposer::isConnected(PhysicalDisplayId displayId) const {
    if (mDisplayData.count(displayId)) {
        return mDisplayData.at(displayId).hwcDisplay->isConnected();
    }

    return false;
    return mDisplayData.count(displayId) && mDisplayData.at(displayId).hwcDisplay->isConnected();
}

std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId displayId) const {
@@ -946,18 +942,15 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect(
        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 {
    if (!isConnected(*displayId)) {
        LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Already disconnected");
        return {};
    }
    // 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};

    // The display will later be destroyed by a call to HWComposer::disconnectDisplay. For now, mark
    // it as disconnected.
    mDisplayData.at(*displayId).hwcDisplay->setConnected(false);
    return DisplayIdentificationInfo{.id = *displayId};
}

void HWComposer::loadCapabilities() {
+58 −57
Original line number Diff line number Diff line
@@ -2649,72 +2649,73 @@ bool SurfaceFlinger::configureLocked() {
        events = std::move(mPendingHotplugEvents);
    }

    for (const auto& event : events) {
        std::optional<DisplayIdentificationInfo> info =
                getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
    for (const auto [hwcDisplayId, connection] : events) {
        if (auto info = getHwComposer().onHotplug(hwcDisplayId, connection)) {
            const auto displayId = info->id;
            const bool connected = connection == hal::Connection::CONNECTED;

        if (!info) {
            continue;
            if (const char* const log =
                        processHotplug(displayId, hwcDisplayId, connected, std::move(*info))) {
                ALOGI("%s display %s (HAL ID %" PRIu64 ")", log, to_string(displayId).c_str(),
                      hwcDisplayId);
            }
        }
    }

        const auto displayId = info->id;
        const auto token = mPhysicalDisplayTokens.get(displayId);
        const char* log;
    return !events.empty();
}

const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId,
                                           hal::HWDisplayId hwcDisplayId, bool connected,
                                           DisplayIdentificationInfo&& info) {
    const auto tokenOpt = mPhysicalDisplayTokens.get(displayId);
    if (!connected) {
        LOG_ALWAYS_FATAL_IF(!tokenOpt);

        if (const ssize_t index = mCurrentState.displays.indexOfKey(tokenOpt->get()); index >= 0) {
            const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
            mInterceptor->saveDisplayDeletion(state.sequenceId);
            mCurrentState.displays.removeItemsAt(index);
        }

        mPhysicalDisplayTokens.erase(displayId);
        return "Disconnecting";
    }

        if (event.connection == hal::Connection::CONNECTED) {
    auto [supportedModes, activeMode] = loadDisplayModes(displayId);
    if (!activeMode) {
        // TODO(b/241286153): Report hotplug failure to the framework.
        ALOGE("Failed to hotplug display %s", to_string(displayId).c_str());
        getHwComposer().disconnectDisplay(displayId);
                continue;
        return nullptr;
    }

            if (!token) {
                log = "Connecting";
    if (tokenOpt) {
        auto& state = mCurrentState.displays.editValueFor(tokenOpt->get());
        state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
        state.physical->supportedModes = std::move(supportedModes);
        state.physical->activeMode = std::move(activeMode);
        if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) {
            state.physical->deviceProductInfo = std::move(info.deviceProductInfo);
        }
        return "Reconnecting";
    }

    DisplayDeviceState state;
    state.physical = {.id = displayId,
                      .type = getHwComposer().getDisplayConnectionType(displayId),
                                  .hwcDisplayId = event.hwcDisplayId,
                                  .deviceProductInfo = std::move(info->deviceProductInfo),
                      .hwcDisplayId = hwcDisplayId,
                      .deviceProductInfo = std::move(info.deviceProductInfo),
                      .supportedModes = std::move(supportedModes),
                      .activeMode = std::move(activeMode)};
    state.isSecure = true; // All physical displays are currently considered secure.
                state.displayName = std::move(info->name);
    state.displayName = std::move(info.name);

    sp<IBinder> token = sp<BBinder>::make();
    mCurrentState.displays.add(token, state);
    mPhysicalDisplayTokens.try_emplace(displayId, std::move(token));
    mInterceptor->saveDisplayCreation(state);
            } else {
                log = "Reconnecting";

                auto& state = mCurrentState.displays.editValueFor(token->get());
                state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
                state.physical->supportedModes = std::move(supportedModes);
                state.physical->activeMode = std::move(activeMode);
                if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) {
                    state.physical->deviceProductInfo = std::move(info->deviceProductInfo);
                }
            }
        } else {
            log = "Disconnecting";

            if (const ssize_t index = mCurrentState.displays.indexOfKey(token->get()); index >= 0) {
                const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
                mInterceptor->saveDisplayDeletion(state.sequenceId);
                mCurrentState.displays.removeItemsAt(index);
            }

            mPhysicalDisplayTokens.erase(displayId);
        }

        ALOGI("%s display %s (HAL ID %" PRIu64 ")", log, to_string(displayId).c_str(),
              event.hwcDisplayId);
    }

    return !events.empty();
    return "Connecting";
}

void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
+5 −0
Original line number Diff line number Diff line
@@ -915,6 +915,11 @@ private:
    bool configureLocked() REQUIRES(mStateLock) REQUIRES(kMainThreadContext)
            EXCLUDES(mHotplugMutex);

    // Returns a string describing the hotplug, or nullptr if it was rejected.
    const char* processHotplug(PhysicalDisplayId, hal::HWDisplayId, bool connected,
                               DisplayIdentificationInfo&&) REQUIRES(mStateLock)
            REQUIRES(kMainThreadContext);

    sp<DisplayDevice> setupNewDisplayDeviceInternal(
            const wp<IBinder>& displayToken,
            std::shared_ptr<compositionengine::Display> compositionDisplay,
+36 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ TEST_F(HotplugTest, schedulesConfigureToProcessHotplugEvents) {
}

TEST_F(HotplugTest, schedulesFrameToCommitDisplayTransaction) {
    EXPECT_CALL(*mFlinger.scheduler(), scheduleConfigure()).Times(1);
    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);

    constexpr HWDisplayId displayId1 = 456;
@@ -52,6 +53,39 @@ TEST_F(HotplugTest, schedulesFrameToCommitDisplayTransaction) {
    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
}

TEST_F(HotplugTest, ignoresDuplicateDisconnection) {
    // Inject a primary display.
    PrimaryDisplayVariant::injectHwcDisplay(this);

    using ExternalDisplay = ExternalDisplayVariant;
    ExternalDisplay::setupHwcHotplugCallExpectations(this);
    ExternalDisplay::setupHwcGetActiveConfigCallExpectations(this);

    // TODO(b/241286146): Remove this unnecessary call.
    EXPECT_CALL(*mComposer,
                setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
            .WillOnce(Return(Error::NONE));

    // A single commit should be scheduled for both configure calls.
    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);

    ExternalDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED);
    mFlinger.configure();

    EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID));

    // Disconnecting a display that was already disconnected should be a no-op.
    ExternalDisplay::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
    ExternalDisplay::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
    ExternalDisplay::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
    mFlinger.configure();

    // The display should be scheduled for removal during the next commit. At this point, it should
    // still exist but be marked as disconnected.
    EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID));
    EXPECT_FALSE(mFlinger.getHwComposer().isConnected(ExternalDisplay::DISPLAY_ID::get()));
}

TEST_F(HotplugTest, rejectsHotplugIfFailedToLoadDisplayModes) {
    // Inject a primary display.
    PrimaryDisplayVariant::injectHwcDisplay(this);
@@ -70,6 +104,8 @@ TEST_F(HotplugTest, rejectsHotplugIfFailedToLoadDisplayModes) {
                setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
            .WillOnce(Return(Error::NONE));

    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);

    ExternalDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED);
    mFlinger.configure();