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

Commit 6d68b18f authored by Ana Krulec's avatar Ana Krulec Committed by Android (Google) Code Review
Browse files

Merge "Fixing threading around mConnections in Scheduler"

parents 395379b4 6ddd261d
Loading
Loading
Loading
Loading
+57 −12
Original line number Diff line number Diff line
@@ -229,6 +229,7 @@ Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThr
    auto connection =
            createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);

    std::lock_guard<std::mutex> lock(mConnectionsLock);
    mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
    return handle;
}
@@ -240,29 +241,47 @@ sp<EventThreadConnection> Scheduler::createConnectionInternal(

sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
        ConnectionHandle handle, ISurfaceComposer::ConfigChanged configChanged) {
    std::lock_guard<std::mutex> lock(mConnectionsLock);
    RETURN_IF_INVALID_HANDLE(handle, nullptr);
    return createConnectionInternal(mConnections[handle].thread.get(), configChanged);
}

sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) {
    std::lock_guard<std::mutex> lock(mConnectionsLock);
    RETURN_IF_INVALID_HANDLE(handle, nullptr);
    return mConnections[handle].connection;
}

void Scheduler::onHotplugReceived(ConnectionHandle handle, PhysicalDisplayId displayId,
                                  bool connected) {
    android::EventThread* thread;
    {
        std::lock_guard<std::mutex> lock(mConnectionsLock);
        RETURN_IF_INVALID_HANDLE(handle);
    mConnections[handle].thread->onHotplugReceived(displayId, connected);
        thread = mConnections[handle].thread.get();
    }

    thread->onHotplugReceived(displayId, connected);
}

void Scheduler::onScreenAcquired(ConnectionHandle handle) {
    android::EventThread* thread;
    {
        std::lock_guard<std::mutex> lock(mConnectionsLock);
        RETURN_IF_INVALID_HANDLE(handle);
    mConnections[handle].thread->onScreenAcquired();
        thread = mConnections[handle].thread.get();
    }
    thread->onScreenAcquired();
}

void Scheduler::onScreenReleased(ConnectionHandle handle) {
    android::EventThread* thread;
    {
        std::lock_guard<std::mutex> lock(mConnectionsLock);
        RETURN_IF_INVALID_HANDLE(handle);
    mConnections[handle].thread->onScreenReleased();
        thread = mConnections[handle].thread.get();
    }
    thread->onScreenReleased();
}

void Scheduler::onPrimaryDisplayConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
@@ -274,6 +293,16 @@ void Scheduler::onPrimaryDisplayConfigChanged(ConnectionHandle handle, PhysicalD
}

void Scheduler::dispatchCachedReportedConfig() {
    // Check optional fields first.
    if (!mFeatures.configId.has_value()) {
        ALOGW("No config ID found, not dispatching cached config.");
        return;
    }
    if (!mFeatures.cachedConfigChangedParams.has_value()) {
        ALOGW("No config changed params found, not dispatching cached config.");
        return;
    }

    const auto configId = *mFeatures.configId;
    const auto vsyncPeriod =
            mRefreshRateConfigs.getRefreshRateFromConfigId(configId).getVsyncPeriod();
@@ -295,24 +324,40 @@ void Scheduler::dispatchCachedReportedConfig() {
void Scheduler::onNonPrimaryDisplayConfigChanged(ConnectionHandle handle,
                                                 PhysicalDisplayId displayId,
                                                 HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
    android::EventThread* thread;
    {
        std::lock_guard<std::mutex> lock(mConnectionsLock);
        RETURN_IF_INVALID_HANDLE(handle);
    mConnections[handle].thread->onConfigChanged(displayId, configId, vsyncPeriod);
        thread = mConnections[handle].thread.get();
    }
    thread->onConfigChanged(displayId, configId, vsyncPeriod);
}

size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
    std::lock_guard<std::mutex> lock(mConnectionsLock);
    RETURN_IF_INVALID_HANDLE(handle, 0);
    return mConnections[handle].thread->getEventThreadConnectionCount();
}

void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
    android::EventThread* thread;
    {
        std::lock_guard<std::mutex> lock(mConnectionsLock);
        RETURN_IF_INVALID_HANDLE(handle);
    mConnections.at(handle).thread->dump(result);
        thread = mConnections.at(handle).thread.get();
    }
    thread->dump(result);
}

void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds workDuration,
                            std::chrono::nanoseconds readyDuration) {
    android::EventThread* thread;
    {
        std::lock_guard<std::mutex> lock(mConnectionsLock);
        RETURN_IF_INVALID_HANDLE(handle);
    mConnections[handle].thread->setDuration(workDuration, readyDuration);
        thread = mConnections[handle].thread.get();
    }
    thread->setDuration(workDuration, readyDuration);
}

void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats, nsecs_t now) {
+2 −1
Original line number Diff line number Diff line
@@ -228,7 +228,8 @@ private:
    };

    ConnectionHandle::Id mNextConnectionHandleId = 0;
    std::unordered_map<ConnectionHandle, Connection> mConnections;
    mutable std::mutex mConnectionsLock;
    std::unordered_map<ConnectionHandle, Connection> mConnections GUARDED_BY(mConnectionsLock);

    bool mInjectVSyncs = false;
    InjectVSyncSource* mVSyncInjector = nullptr;
+21 −0
Original line number Diff line number Diff line
@@ -175,4 +175,25 @@ TEST_F(SchedulerTest, noLayerHistory) {
    mScheduler.chooseRefreshRateForContent();
}

TEST_F(SchedulerTest, testDispatchCachedReportedConfig) {
    // If the optional fields are cleared, the function should return before
    // onConfigChange is called.
    mScheduler.clearOptionalFieldsInFeatures();
    EXPECT_NO_FATAL_FAILURE(mScheduler.dispatchCachedReportedConfig());
    EXPECT_CALL(*mEventThread, onConfigChanged(_, _, _)).Times(0);
}

TEST_F(SchedulerTest, onNonPrimaryDisplayConfigChanged_invalidParameters) {
    HwcConfigIndexType configId = HwcConfigIndexType(111);
    nsecs_t vsyncPeriod = 111111;

    // If the handle is incorrect, the function should return before
    // onConfigChange is called.
    Scheduler::ConnectionHandle invalidHandle = {.id = 123};
    EXPECT_NO_FATAL_FAILURE(mScheduler.onNonPrimaryDisplayConfigChanged(invalidHandle,
                                                                        PHYSICAL_DISPLAY_ID,
                                                                        configId, vsyncPeriod));
    EXPECT_CALL(*mEventThread, onConfigChanged(_, _, _)).Times(0);
}

} // namespace android
+17 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#pragma once

#include <Scheduler/Scheduler.h>
#include <gmock/gmock.h>
#include <gui/ISurfaceComposer.h>

@@ -93,6 +94,22 @@ public:
        return mFeatures.touch == Scheduler::TouchState::Active;
    }

    void dispatchCachedReportedConfig() {
        std::lock_guard<std::mutex> lock(mFeatureStateLock);
        return Scheduler::dispatchCachedReportedConfig();
    }

    void clearOptionalFieldsInFeatures() {
        std::lock_guard<std::mutex> lock(mFeatureStateLock);
        mFeatures.cachedConfigChangedParams.reset();
    }

    void onNonPrimaryDisplayConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
                                          HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
        return Scheduler::onNonPrimaryDisplayConfigChanged(handle, displayId, configId,
                                                           vsyncPeriod);
    }

    ~TestableScheduler() {
        // All these pointer and container clears help ensure that GMock does
        // not report a leaked object, since the Scheduler instance may