SF: Fix thread safety for scheduler callbacks
SurfaceFlinger::setRefreshRateTo, called from the Scheduler callbacks,
reads HWC and SF state without locking mStateLock, concurrently with
writes from the main thread. This CL registers ResetIdleTimerCallback
per EventThreadConnection, and locks mStateLock for connections used
off the main thread. Note that ExpiredTimerCallback locks mStateLock
unconditionally, since it is always called from the IdleTimer thread.
This CL also adds a thread annotation to setRefreshRateTo, and refactors
it accordingly.
Bug: 123715322
Test: libsurfaceflinger_unittest
Test: Boot with scheduler enabled
Change-Id: Id62c48ae22da38f292ffc18e8731a1c49a0a083c
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 91ae087..5d9cfde 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -100,8 +100,10 @@
} // namespace
EventThreadConnection::EventThreadConnection(EventThread* eventThread,
- ResyncCallback resyncCallback)
+ ResyncCallback resyncCallback,
+ ResetIdleTimerCallback resetIdleTimerCallback)
: resyncCallback(std::move(resyncCallback)),
+ resetIdleTimerCallback(std::move(resetIdleTimerCallback)),
mEventThread(eventThread),
mChannel(gui::BitTube::DefaultSize) {}
@@ -147,22 +149,18 @@
namespace impl {
EventThread::EventThread(std::unique_ptr<VSyncSource> src,
- const InterceptVSyncsCallback& interceptVSyncsCallback,
- const ResetIdleTimerCallback& resetIdleTimerCallback,
- const char* threadName)
- : EventThread(nullptr, std::move(src), interceptVSyncsCallback, threadName) {
- mResetIdleTimer = resetIdleTimerCallback;
-}
+ InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
+ : EventThread(nullptr, std::move(src), std::move(interceptVSyncsCallback), threadName) {}
EventThread::EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
const char* threadName)
- : EventThread(src, nullptr, interceptVSyncsCallback, threadName) {}
+ : EventThread(src, nullptr, std::move(interceptVSyncsCallback), threadName) {}
EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
: mVSyncSource(src),
mVSyncSourceUnique(std::move(uniqueSrc)),
- mInterceptVSyncsCallback(interceptVSyncsCallback),
+ mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
mThreadName(threadName) {
if (src == nullptr) {
mVSyncSource = mVSyncSourceUnique.get();
@@ -205,8 +203,10 @@
mVSyncSource->setPhaseOffset(phaseOffset);
}
-sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const {
- return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback));
+sp<EventThreadConnection> EventThread::createEventConnection(
+ ResyncCallback resyncCallback, ResetIdleTimerCallback resetIdleTimerCallback) const {
+ return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
+ std::move(resetIdleTimerCallback));
}
status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -249,9 +249,9 @@
}
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) {
- if (mResetIdleTimer && reset) {
+ if (connection->resetIdleTimerCallback && reset) {
ATRACE_NAME("resetIdleTimer");
- mResetIdleTimer();
+ connection->resetIdleTimerCallback();
}
if (connection->resyncCallback) {
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 62b6a8b..b275183 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -45,6 +45,7 @@
// ---------------------------------------------------------------------------
using ResyncCallback = std::function<void()>;
+using ResetIdleTimerCallback = std::function<void()>;
enum class VSyncRequest {
None = -1,
@@ -69,7 +70,7 @@
class EventThreadConnection : public BnDisplayEventConnection {
public:
- EventThreadConnection(EventThread* eventThread, ResyncCallback resyncCallback);
+ EventThreadConnection(EventThread*, ResyncCallback, ResetIdleTimerCallback);
virtual ~EventThreadConnection();
virtual status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -83,6 +84,7 @@
// Called in response to requestNextVsync.
const ResyncCallback resyncCallback;
+ const ResetIdleTimerCallback resetIdleTimerCallback;
VSyncRequest vsyncRequest = VSyncRequest::None;
@@ -96,8 +98,8 @@
public:
virtual ~EventThread();
- virtual sp<EventThreadConnection> createEventConnection(
- ResyncCallback resyncCallback) const = 0;
+ virtual sp<EventThreadConnection> createEventConnection(ResyncCallback,
+ ResetIdleTimerCallback) const = 0;
// called before the screen is turned off from main thread
virtual void onScreenReleased() = 0;
@@ -124,17 +126,14 @@
class EventThread : public android::EventThread, private VSyncSource::Callback {
public:
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
- using ResetIdleTimerCallback = std::function<void()>;
// TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
- EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
- const char* threadName);
- EventThread(std::unique_ptr<VSyncSource> src,
- const InterceptVSyncsCallback& interceptVSyncsCallback,
- const ResetIdleTimerCallback& resetIdleTimerCallback, const char* threadName);
+ EventThread(VSyncSource*, InterceptVSyncsCallback, const char* threadName);
+ EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName);
~EventThread();
- sp<EventThreadConnection> createEventConnection(ResyncCallback resyncCallback) const override;
+ sp<EventThreadConnection> createEventConnection(ResyncCallback,
+ ResetIdleTimerCallback) const override;
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
@@ -220,9 +219,6 @@
State mState GUARDED_BY(mMutex) = State::Idle;
static const char* toCString(State);
-
- // Callback that resets the idle timer when the next vsync is received.
- ResetIdleTimerCallback mResetIdleTimer;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 75a410b..1f18ead 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -96,7 +96,8 @@
}
mEventThread = eventThread;
- mEvents = eventThread->createEventConnection(std::move(resyncCallback));
+ mEvents =
+ eventThread->createEventConnection(std::move(resyncCallback), ResetIdleTimerCallback());
mEvents->stealReceiveChannel(&mEventTube);
mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
this);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 3060f1d..2f581d2 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -87,6 +87,7 @@
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
+ ResetIdleTimerCallback resetIdleTimerCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
@@ -94,12 +95,14 @@
std::unique_ptr<EventThread> eventThread =
makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
std::move(interceptCallback));
- auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
- eventThread->createEventConnection(
- std::move(resyncCallback)),
- std::move(eventThread));
- mConnections.insert(std::make_pair(id, std::move(connection)));
+ auto eventThreadConnection =
+ createConnectionInternal(eventThread.get(), std::move(resyncCallback),
+ std::move(resetIdleTimerCallback));
+ mConnections.emplace(id,
+ std::make_unique<Connection>(new ConnectionHandle(id),
+ eventThreadConnection,
+ std::move(eventThread)));
return mConnections[id]->handle;
}
@@ -109,14 +112,29 @@
std::unique_ptr<VSyncSource> eventThreadSource =
std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
- std::move(interceptCallback),
- [this] { resetIdleTimer(); }, connectionName);
+ std::move(interceptCallback), connectionName);
+}
+
+sp<EventThreadConnection> Scheduler::createConnectionInternal(
+ EventThread* eventThread, ResyncCallback&& resyncCallback,
+ ResetIdleTimerCallback&& resetIdleTimerCallback) {
+ return eventThread->createEventConnection(std::move(resyncCallback),
+ [this,
+ resetIdleTimerCallback =
+ std::move(resetIdleTimerCallback)] {
+ resetIdleTimer();
+ if (resetIdleTimerCallback) {
+ resetIdleTimerCallback();
+ }
+ });
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
+ const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
+ ResetIdleTimerCallback resetIdleTimerCallback) {
RETURN_VALUE_IF_INVALID(nullptr);
- return mConnections[handle->id]->thread->createEventConnection(std::move(resyncCallback));
+ return createConnectionInternal(mConnections[handle->id]->thread.get(),
+ std::move(resyncCallback), std::move(resetIdleTimerCallback));
}
EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -241,11 +259,6 @@
mExpiredTimerCallback = expiredTimerCallback;
}
-void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- mResetTimerCallback = resetTimerCallback;
-}
-
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
ATRACE_INT("FrameSkipCount", skipCount);
if (mSkipCount != skipCount) {
@@ -336,11 +349,6 @@
mIdleTimer->reset();
ATRACE_INT("ExpiredIdleTimer", 0);
}
-
- std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mResetTimerCallback) {
- mResetTimerCallback();
- }
}
void Scheduler::expiredTimerCallback() {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index e77dc06..4abf027 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -37,7 +37,6 @@
class Scheduler {
public:
using ExpiredIdleTimerCallback = std::function<void()>;
- using ResetIdleTimerCallback = std::function<void()>;
// Enum to indicate whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
@@ -72,12 +71,13 @@
virtual ~Scheduler();
/** Creates an EventThread connection. */
- sp<ConnectionHandle> createConnection(
- const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
- impl::EventThread::InterceptVSyncsCallback interceptCallback);
+ sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs,
+ ResyncCallback, ResetIdleTimerCallback,
+ impl::EventThread::InterceptVSyncsCallback);
sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
- ResyncCallback resyncCallback);
+ ResyncCallback,
+ ResetIdleTimerCallback);
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -116,8 +116,6 @@
void incrementFrameCounter();
// Callback that gets invoked once the idle timer expires.
void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
- // Callback that gets invoked once the idle timer is reset.
- void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
// Returns relevant information about Scheduler for dumpsys purposes.
std::string doDump();
@@ -127,6 +125,10 @@
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
+ // Creates a connection on the given EventThread and forwards the given callbacks.
+ sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
+ ResetIdleTimerCallback&&);
+
nsecs_t calculateAverage() const;
void updateFrameSkipping(const int64_t skipCount);
// Collects the statistical mean (average) and median between timestamp
@@ -184,7 +186,6 @@
std::mutex mCallbackLock;
ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
- ResetIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
};
} // namespace android