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 Original line Diff line number Diff line
@@ -252,11 +252,7 @@ std::shared_ptr<HWC2::Layer> HWComposer::createLayer(HalDisplayId displayId) {
}
}


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

    return false;
}
}


std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId displayId) const {
std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId displayId) const {
@@ -946,18 +942,15 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect(
        return {};
        return {};
    }
    }


    // The display will later be destroyed by a call to
    if (!isConnected(*displayId)) {
    // destroyDisplay(). For now we just mark it disconnected.
    if (isConnected(*displayId)) {
        mDisplayData[*displayId].hwcDisplay->setConnected(false);
    } else {
        LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Already disconnected");
        LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Already disconnected");
        return {};
    }
    }
    // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay

    // via SurfaceFlinger's onHotplugReceived callback handling
    // The display will later be destroyed by a call to HWComposer::disconnectDisplay. For now, mark
    return DisplayIdentificationInfo{.id = *displayId,
    // it as disconnected.
                                     .name = std::string(),
    mDisplayData.at(*displayId).hwcDisplay->setConnected(false);
                                     .deviceProductInfo = std::nullopt};
    return DisplayIdentificationInfo{.id = *displayId};
}
}


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


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


        if (!info) {
            if (const char* const log =
            continue;
                        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;
    return !events.empty();
        const auto token = mPhysicalDisplayTokens.get(displayId);
}
        const char* log;

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);
    auto [supportedModes, activeMode] = loadDisplayModes(displayId);
    if (!activeMode) {
    if (!activeMode) {
        // TODO(b/241286153): Report hotplug failure to the framework.
        // TODO(b/241286153): Report hotplug failure to the framework.
        ALOGE("Failed to hotplug display %s", to_string(displayId).c_str());
        ALOGE("Failed to hotplug display %s", to_string(displayId).c_str());
        getHwComposer().disconnectDisplay(displayId);
        getHwComposer().disconnectDisplay(displayId);
                continue;
        return nullptr;
    }
    }


            if (!token) {
    if (tokenOpt) {
                log = "Connecting";
        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;
    DisplayDeviceState state;
    state.physical = {.id = displayId,
    state.physical = {.id = displayId,
                      .type = getHwComposer().getDisplayConnectionType(displayId),
                      .type = getHwComposer().getDisplayConnectionType(displayId),
                                  .hwcDisplayId = event.hwcDisplayId,
                      .hwcDisplayId = hwcDisplayId,
                                  .deviceProductInfo = std::move(info->deviceProductInfo),
                      .deviceProductInfo = std::move(info.deviceProductInfo),
                      .supportedModes = std::move(supportedModes),
                      .supportedModes = std::move(supportedModes),
                      .activeMode = std::move(activeMode)};
                      .activeMode = std::move(activeMode)};
    state.isSecure = true; // All physical displays are currently considered secure.
    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();
    sp<IBinder> token = sp<BBinder>::make();
    mCurrentState.displays.add(token, state);
    mCurrentState.displays.add(token, state);
    mPhysicalDisplayTokens.try_emplace(displayId, std::move(token));
    mPhysicalDisplayTokens.try_emplace(displayId, std::move(token));
    mInterceptor->saveDisplayCreation(state);
    mInterceptor->saveDisplayCreation(state);
            } else {
    return "Connecting";
                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();
}
}


void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
+5 −0
Original line number Original line Diff line number Diff line
@@ -915,6 +915,11 @@ private:
    bool configureLocked() REQUIRES(mStateLock) REQUIRES(kMainThreadContext)
    bool configureLocked() REQUIRES(mStateLock) REQUIRES(kMainThreadContext)
            EXCLUDES(mHotplugMutex);
            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(
    sp<DisplayDevice> setupNewDisplayDeviceInternal(
            const wp<IBinder>& displayToken,
            const wp<IBinder>& displayToken,
            std::shared_ptr<compositionengine::Display> compositionDisplay,
            std::shared_ptr<compositionengine::Display> compositionDisplay,
+36 −0
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ TEST_F(HotplugTest, schedulesConfigureToProcessHotplugEvents) {
}
}


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


    constexpr HWDisplayId displayId1 = 456;
    constexpr HWDisplayId displayId1 = 456;
@@ -52,6 +53,39 @@ TEST_F(HotplugTest, schedulesFrameToCommitDisplayTransaction) {
    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
    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) {
TEST_F(HotplugTest, rejectsHotplugIfFailedToLoadDisplayModes) {
    // Inject a primary display.
    // Inject a primary display.
    PrimaryDisplayVariant::injectHwcDisplay(this);
    PrimaryDisplayVariant::injectHwcDisplay(this);
@@ -70,6 +104,8 @@ TEST_F(HotplugTest, rejectsHotplugIfFailedToLoadDisplayModes) {
                setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
                setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
            .WillOnce(Return(Error::NONE));
            .WillOnce(Return(Error::NONE));


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

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