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

Commit 0bb6a47f authored by Ady Abraham's avatar Ady Abraham
Browse files

SurfaceFlinger: throttle applications based on uid

Add the ability for SurfaceFlinger to be able to throttle down to
a divider of the refresh rate (i.e. for 30/45 for 90Hz)

Change-Id: I6bfd6f43ee1f30e771a136c558d8ae9a6d7fbe0f
Test: Manually via 1039 SF backdoor
Bug: 170502573
Bug: 169270763
Bug: 169271059
parent 9febda8e
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -393,6 +393,15 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
                              nsecs_t expectedPresentTime) {
    ATRACE_CALL();

    // If this is not a valid vsync for the layer's uid, return and try again later
    const bool isVsyncValidForUid =
            mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid);
    if (!isVsyncValidForUid) {
        ATRACE_NAME("!isVsyncValidForUid");
        mFlinger->setTransactionFlags(eTraversalNeeded);
        return false;
    }

    bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);

    if (refreshRequired) {
+26 −5
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@

#include <android-base/stringprintf.h>

#include <binder/IPCThreadState.h>

#include <cutils/compiler.h>
#include <cutils/sched_policy.h>

@@ -123,11 +125,12 @@ DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId,

} // namespace

EventThreadConnection::EventThreadConnection(EventThread* eventThread,
EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid,
                                             ResyncCallback resyncCallback,
                                             ISurfaceComposer::ConfigChanged configChanged)
      : resyncCallback(std::move(resyncCallback)),
        mConfigChanged(configChanged),
        mOwnerUid(callingUid),
        mEventThread(eventThread),
        mChannel(gui::BitTube::DefaultSize) {}

@@ -170,10 +173,12 @@ namespace impl {

EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
                         android::frametimeline::TokenManager* tokenManager,
                         InterceptVSyncsCallback interceptVSyncsCallback)
                         InterceptVSyncsCallback interceptVSyncsCallback,
                         ThrottleVsyncCallback throttleVsyncCallback)
      : mVSyncSource(std::move(vsyncSource)),
        mTokenManager(tokenManager),
        mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
        mThrottleVsyncCallback(std::move(throttleVsyncCallback)),
        mThreadName(mVSyncSource->getName()) {
    mVSyncSource->setCallback(this);

@@ -216,8 +221,9 @@ void EventThread::setDuration(std::chrono::nanoseconds workDuration,

sp<EventThreadConnection> EventThread::createEventConnection(
        ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const {
    return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
                                     configChanged);
    return new EventThreadConnection(const_cast<EventThread*>(this),
                                     IPCThreadState::self()->getCallingUid(),
                                     std::move(resyncCallback), configChanged);
}

status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -443,6 +449,11 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {

bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
                                     const sp<EventThreadConnection>& connection) const {
    const auto throttleVsync = [&] {
        return mThrottleVsyncCallback &&
                mThrottleVsyncCallback(event.vsync.expectedVSyncTimestamp, connection->mOwnerUid);
    };

    switch (event.header.type) {
        case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
            return true;
@@ -458,12 +469,22 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
                case VSyncRequest::SingleSuppressCallback:
                    connection->vsyncRequest = VSyncRequest::None;
                    return false;
                case VSyncRequest::Single:
                case VSyncRequest::Single: {
                    if (throttleVsync()) {
                        return false;
                    }
                    connection->vsyncRequest = VSyncRequest::SingleSuppressCallback;
                    return true;
                }
                case VSyncRequest::Periodic:
                    if (throttleVsync()) {
                        return false;
                    }
                    return true;
                default:
                    // We don't throttle vsync if the app set a vsync request rate
                    // since there is no easy way to do that and this is a very
                    // rare case
                    return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0;
            }

+7 −3
Original line number Diff line number Diff line
@@ -81,7 +81,7 @@ public:

class EventThreadConnection : public BnDisplayEventConnection {
public:
    EventThreadConnection(EventThread*, ResyncCallback,
    EventThreadConnection(EventThread*, uid_t callingUid, ResyncCallback,
                          ISurfaceComposer::ConfigChanged configChanged);
    virtual ~EventThreadConnection();

@@ -98,6 +98,8 @@ public:
    const ISurfaceComposer::ConfigChanged mConfigChanged =
            ISurfaceComposer::ConfigChanged::eConfigChangedSuppress;

    const uid_t mOwnerUid;

private:
    virtual void onFirstRef();
    EventThread* const mEventThread;
@@ -143,9 +145,10 @@ namespace impl {
class EventThread : public android::EventThread, private VSyncSource::Callback {
public:
    using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
    using ThrottleVsyncCallback = std::function<bool(nsecs_t, uid_t)>;

    EventThread(std::unique_ptr<VSyncSource>, frametimeline::TokenManager*,
                InterceptVSyncsCallback);
    EventThread(std::unique_ptr<VSyncSource>, frametimeline::TokenManager*, InterceptVSyncsCallback,
                ThrottleVsyncCallback);
    ~EventThread();

    sp<EventThreadConnection> createEventConnection(
@@ -196,6 +199,7 @@ private:
    frametimeline::TokenManager* const mTokenManager;

    const InterceptVSyncsCallback mInterceptVSyncsCallback;
    const ThrottleVsyncCallback mThrottleVsyncCallback;
    const char* const mThreadName;

    std::thread mThread;
+32 −0
Original line number Diff line number Diff line
@@ -625,4 +625,36 @@ RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction
    return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
}

void RefreshRateConfigs::setPreferredRefreshRateForUid(uid_t uid, float refreshRateHz) {
    if (refreshRateHz > 0 && refreshRateHz < 1) {
        return;
    }

    std::lock_guard lock(mLock);
    if (refreshRateHz != 0) {
        mPreferredRefreshRateForUid[uid] = refreshRateHz;
    } else {
        mPreferredRefreshRateForUid.erase(uid);
    }
}

int RefreshRateConfigs::getRefreshRateDividerForUid(uid_t uid) const {
    constexpr float kThreshold = 0.1f;
    std::lock_guard lock(mLock);

    const auto iter = mPreferredRefreshRateForUid.find(uid);
    if (iter == mPreferredRefreshRateForUid.end()) {
        return 1;
    }

    const auto refreshRateHz = iter->second;
    const auto numPeriods = mCurrentRefreshRate->getFps() / refreshRateHz;
    const auto numPeriodsRounded = std::round(numPeriods);
    if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) {
        return 1;
    }

    return static_cast<int>(numPeriods);
}

} // namespace android::scheduler
+9 −0
Original line number Diff line number Diff line
@@ -311,6 +311,13 @@ public:
    // refresh rates.
    KernelIdleTimerAction getIdleTimerAction() const;

    // Stores the preferred refresh rate that an app should run at.
    // refreshRate == 0 means no preference.
    void setPreferredRefreshRateForUid(uid_t, float refreshRateHz) EXCLUDES(mLock);

    // Returns a divider for the current refresh rate
    int getRefreshRateDividerForUid(uid_t) const EXCLUDES(mLock);

private:
    friend class RefreshRateConfigsTest;

@@ -368,6 +375,8 @@ private:
    Policy mDisplayManagerPolicy GUARDED_BY(mLock);
    std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);

    std::unordered_map<uid_t, float> mPreferredRefreshRateForUid GUARDED_BY(mLock);

    // The min and max refresh rates supported by the device.
    // This will not change at runtime.
    const RefreshRate* mMinSupportedRefreshRate;
Loading