/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)

#include "VariableRefreshRateController.h"

#include <android-base/logging.h>
#include <processgroup/sched_policy.h>
#include <sync/sync.h>
#include <utils/Trace.h>

#include "ExynosHWCHelper.h"
#include "drmmode.h"

#include <chrono>
#include <tuple>

#include "RefreshRateCalculator/RefreshRateCalculatorFactory.h"
#include "display/DisplayContextProviderFactory.h"
#include "interface/Panel_def.h"

namespace android::hardware::graphics::composer {

namespace {

using android::hardware::graphics::composer::VrrControllerEventType;

}

static OperationSpeedMode getOperationSpeedModeWrapper(void* host) {
    VariableRefreshRateController* controller =
            reinterpret_cast<VariableRefreshRateController*>(host);
    return controller->getOperationSpeedMode();
}

static BrightnessMode getBrightnessModeWrapper(void* host) {
    VariableRefreshRateController* controller =
            reinterpret_cast<VariableRefreshRateController*>(host);
    return controller->getBrightnessMode();
}

static int getBrightnessNitsWrapper(void* host) {
    VariableRefreshRateController* controller =
            reinterpret_cast<VariableRefreshRateController*>(host);
    return controller->getBrightnessNits();
}

static const char* getDisplayFileNodePathWrapper(void* host) {
    VariableRefreshRateController* controller =
            reinterpret_cast<VariableRefreshRateController*>(host);
    return controller->getDisplayFileNodePath();
}

static int getEstimateVideoFrameRateWrapper(void* host) {
    VariableRefreshRateController* controller =
            reinterpret_cast<VariableRefreshRateController*>(host);
    return controller->getEstimatedVideoFrameRate();
}

static int getAmbientLightSensorOutputWrapper(void* host) {
    VariableRefreshRateController* controller =
            reinterpret_cast<VariableRefreshRateController*>(host);
    return controller->getAmbientLightSensorOutput();
}

static bool isProximityThrottlingEnabledWrapper(void* host) {
    VariableRefreshRateController* controller =
            reinterpret_cast<VariableRefreshRateController*>(host);
    return controller->isProximityThrottlingEnabled();
}

auto VariableRefreshRateController::CreateInstance(ExynosDisplay* display,
                                                   const std::string& panelName)
        -> std::shared_ptr<VariableRefreshRateController> {
    if (!display) {
        LOG(ERROR)
                << "VrrController: create VariableRefreshRateController without display handler.";
        return nullptr;
    }
    auto controller = std::shared_ptr<VariableRefreshRateController>(
            new VariableRefreshRateController(display, panelName));
    std::thread thread = std::thread(&VariableRefreshRateController::threadBody, controller.get());
    std::string threadName = "VrrCtrl_";
    threadName += display->mIndex == 0 ? "Primary" : "Second";
    int error = pthread_setname_np(thread.native_handle(), threadName.c_str());
    if (error != 0) {
        LOG(WARNING) << "VrrController: Unable to set thread name, error = " << strerror(error);
    }
    thread.detach();

    return controller;
}

VariableRefreshRateController::VariableRefreshRateController(ExynosDisplay* display,
                                                             const std::string& panelName)
      : mDisplay(display), mPanelName(panelName) {
    mState = VrrControllerState::kDisable;
    std::string displayFileNodePath = mDisplay->getPanelSysfsPath();
    if (displayFileNodePath.empty()) {
        LOG(WARNING) << "VrrController: Cannot find file node of display: "
                     << mDisplay->mDisplayName;
    } else {
        auto& fileNodeManager =
                android::hardware::graphics::composer::FileNodeManager::getInstance();
        mFileNode = fileNodeManager.getFileNode(displayFileNodePath);
        auto content = mFileNode->readString(kRefreshControlNodeName);
        if (!(content.has_value()) ||
            (content.value().compare(0, kRefreshControlNodeEnabled.length(),
                                     kRefreshControlNodeEnabled))) {
            LOG(ERROR) << "VrrController: RefreshControlNode is not enabled";
        }
    }

    // Initialize DisplayContextProviderInterface.
    mDisplayContextProviderInterface.getOperationSpeedMode = (&getOperationSpeedModeWrapper);
    mDisplayContextProviderInterface.getBrightnessMode = (&getBrightnessModeWrapper);
    mDisplayContextProviderInterface.getBrightnessNits = (&getBrightnessNitsWrapper);
    mDisplayContextProviderInterface.getDisplayFileNodePath = (&getDisplayFileNodePathWrapper);
    mDisplayContextProviderInterface.getEstimatedVideoFrameRate =
            (&getEstimateVideoFrameRateWrapper);
    mDisplayContextProviderInterface.getAmbientLightSensorOutput =
            (&getAmbientLightSensorOutputWrapper);
    mDisplayContextProviderInterface.isProximityThrottlingEnabled =
            (&isProximityThrottlingEnabledWrapper);

    // Flow to build refresh rate calculator.
    RefreshRateCalculatorFactory refreshRateCalculatorFactory;
    std::vector<std::shared_ptr<RefreshRateCalculator>> Calculators;

    Calculators.emplace_back(std::move(
            refreshRateCalculatorFactory
                    .BuildRefreshRateCalculator(&mEventQueue, RefreshRateCalculatorType::kAod)));
    Calculators.emplace_back(
            std::move(refreshRateCalculatorFactory
                              .BuildRefreshRateCalculator(&mEventQueue,
                                                          RefreshRateCalculatorType::kExitIdle)));
    // videoFrameRateCalculator will be shared with display context provider.
    auto videoFrameRateCalculator =
            refreshRateCalculatorFactory
                    .BuildRefreshRateCalculator(&mEventQueue,
                                                RefreshRateCalculatorType::kVideoPlayback);
    Calculators.emplace_back(videoFrameRateCalculator);

    PeriodRefreshRateCalculatorParameters peridParams;
    peridParams.mConfidencePercentage = 0;
    Calculators.emplace_back(std::move(
            refreshRateCalculatorFactory.BuildRefreshRateCalculator(&mEventQueue, peridParams)));

    mRefreshRateCalculator =
            refreshRateCalculatorFactory.BuildRefreshRateCalculator(std::move(Calculators));
    mRefreshRateCalculator->registerRefreshRateChangeCallback(
            std::bind(&VariableRefreshRateController::onRefreshRateChanged, this,
                      std::placeholders::_1));

    mPowerModeListeners.push_back(mRefreshRateCalculator.get());

    std::string fullPath = displayFileNodePath + kFrameRateNodeName;
    int fd = open(fullPath.c_str(), O_WRONLY, 0);
    if (fd >= 0) {
        mFrameRateReporter =
                refreshRateCalculatorFactory
                        .BuildRefreshRateCalculator(&mEventQueue,
                                                    RefreshRateCalculatorType::kInstant);
        mFrameRateReporter->registerRefreshRateChangeCallback(
                std::bind(&VariableRefreshRateController::onFrameRateChangedForDBI, this,
                          std::placeholders::_1));
    }

    DisplayContextProviderFactory displayContextProviderFactory(mDisplay, this, &mEventQueue);
    mDisplayContextProvider =
            displayContextProviderFactory
                    .buildDisplayContextProvider(DisplayContextProviderType::kExynos,
                                                 std::move(videoFrameRateCalculator));

    mPresentTimeoutEventHandlerLoader.reset(
            new ExternalEventHandlerLoader(std::string(kVendorDisplayPanelLibrary).c_str(),
                                           &mDisplayContextProviderInterface, this,
                                           mPanelName.c_str()));
    mPresentTimeoutEventHandler = mPresentTimeoutEventHandlerLoader->getEventHandler();

    mVariableRefreshRateStatistic =
            std::make_shared<VariableRefreshRateStatistic>(mDisplayContextProvider.get(),
                                                           &mEventQueue, kMaxFrameRate,
                                                           kMaxTefrequency,
                                                           (1 * std::nano::den /*1 second*/));
    mPowerModeListeners.push_back(mVariableRefreshRateStatistic.get());

    mResidencyWatcher =
            ndk::SharedRefBase::make<DisplayStateResidencyWatcher>(mDisplayContextProvider,
                                                                   mVariableRefreshRateStatistic);
}

VariableRefreshRateController::~VariableRefreshRateController() {
    stopThread(true);

    const std::lock_guard<std::mutex> lock(mMutex);
    if (mLastPresentFence.has_value()) {
        if (close(mLastPresentFence.value())) {
            LOG(ERROR) << "VrrController: close fence file failed, errno = " << errno;
        }
        mLastPresentFence = std::nullopt;
    }
};

int VariableRefreshRateController::notifyExpectedPresent(int64_t timestamp,
                                                         int32_t frameIntervalNs) {
    ATRACE_CALL();
    {
        const std::lock_guard<std::mutex> lock(mMutex);
        mRecord.mNextExpectedPresentTime = {mVrrActiveConfig, timestamp, frameIntervalNs};
        // Post kNotifyExpectedPresentConfig event.
        postEvent(VrrControllerEventType::kNotifyExpectedPresentConfig, getSteadyClockTimeNs());
    }
    mCondition.notify_all();
    return 0;
}

void VariableRefreshRateController::reset() {
    ATRACE_CALL();

    const std::lock_guard<std::mutex> lock(mMutex);
    mEventQueue.mPriorityQueue = std::priority_queue<VrrControllerEvent>();
    mRecord.clear();
    dropEventLocked();
    if (mLastPresentFence.has_value()) {
        if (close(mLastPresentFence.value())) {
            LOG(ERROR) << "VrrController: close fence file failed, errno = " << errno;
        }
        mLastPresentFence = std::nullopt;
    }
}

void VariableRefreshRateController::setActiveVrrConfiguration(hwc2_config_t config) {
    LOG(INFO) << "VrrController: Set active Vrr configuration = " << config
              << ", power mode = " << mPowerMode;
    ATRACE_CALL();
    {
        const std::lock_guard<std::mutex> lock(mMutex);
        if (mVrrConfigs.count(config) == 0) {
            LOG(ERROR) << "VrrController: Set an undefined active configuration";
            return;
        }
        const auto oldMaxFrameRate =
                durationNsToFreq(mVrrConfigs[mVrrActiveConfig].minFrameIntervalNs);
        mVrrActiveConfig = config;
        if (mFrameRateReporter) {
            mFrameRateReporter->onPresent(getSteadyClockTimeNs(), 0);
        }
        // If the minimum refresh rate is active and the maximum refresh rate timeout is set,
        // also we are stay at the maximum refresh rate, any change in the active configuration
        // needs to reconfigure the maximum refresh rate according to the newly activated
        // configuration.
        if (mMinimumRefreshRatePresentStates >= kAtMaximumRefreshRate) {
            if (isMinimumRefreshRateActive() && (mMaximumRefreshRateTimeoutNs > 0)) {
                uint32_t command = getCurrentRefreshControlStateLocked();
                auto newMaxFrameRate = durationNsToFreq(mVrrConfigs[config].minFrameIntervalNs);
                setBitField(command, newMaxFrameRate, kPanelRefreshCtrlMinimumRefreshRateOffset,
                            kPanelRefreshCtrlMinimumRefreshRateMask);
                if (!mFileNode->WriteUint32(composer::kRefreshControlNodeName, command)) {
                    LOG(WARNING) << "VrrController: write file node error, command = " << command;
                }
                onRefreshRateChangedInternal(newMaxFrameRate);
                LOG(INFO) << "VrrController: update maximum refresh rate from " << oldMaxFrameRate
                          << " to " << newMaxFrameRate;
            } else {
                LOG(ERROR) << "VrrController: MinimumRefreshRatePresentState cannot be "
                           << mMinimumRefreshRatePresentStates
                           << " when minimum refresh rate = " << mMinimumRefreshRate
                           << " , mMaximumRefreshRateTimeoutNs = " << mMaximumRefreshRateTimeoutNs;
            }
        }
        if (mVariableRefreshRateStatistic) {
            mVariableRefreshRateStatistic
                    ->setActiveVrrConfiguration(config,
                                                durationNsToFreq(mVrrConfigs[mVrrActiveConfig]
                                                                         .vsyncPeriodNs));
        }
        reportRefreshRateIndicator();
        if (mState == VrrControllerState::kDisable) {
            return;
        }
        mState = VrrControllerState::kRendering;
        dropEventLocked(VrrControllerEventType::kSystemRenderingTimeout);

        if (mVrrConfigs[mVrrActiveConfig].isFullySupported) {
            postEvent(VrrControllerEventType::kSystemRenderingTimeout,
                      getSteadyClockTimeNs() +
                              mVrrConfigs[mVrrActiveConfig].notifyExpectedPresentConfig->TimeoutNs);
        }
        if (mRefreshRateCalculator) {
            mRefreshRateCalculator
                    ->setVrrConfigAttributes(mVrrConfigs[mVrrActiveConfig].vsyncPeriodNs,
                                             mVrrConfigs[mVrrActiveConfig].minFrameIntervalNs);
        }
        if (mFrameRateReporter) {
            mFrameRateReporter
                    ->setVrrConfigAttributes(mVrrConfigs[mVrrActiveConfig].vsyncPeriodNs,
                                             mVrrConfigs[mVrrActiveConfig].minFrameIntervalNs);
        }
    }
    mCondition.notify_all();
}

void VariableRefreshRateController::setEnable(bool isEnabled) {
    ATRACE_CALL();
    {
        const std::lock_guard<std::mutex> lock(mMutex);
        if (mEnabled == isEnabled) {
            return;
        }
        mEnabled = isEnabled;
        if (mEnabled == false) {
            dropEventLocked();
        }
    }
    mCondition.notify_all();
}

void VariableRefreshRateController::preSetPowerMode(int32_t powerMode) {
    ATRACE_CALL();
    LOG(INFO) << "VrrController: preSet power mode to " << powerMode << ", from " << mPowerMode;
    {
        const std::lock_guard<std::mutex> lock(mMutex);
        if (mPowerMode == powerMode) {
            return;
        }
        switch (powerMode) {
            case HWC_POWER_MODE_DOZE:
            case HWC_POWER_MODE_DOZE_SUSPEND: {
                uint32_t command = getCurrentRefreshControlStateLocked();
                setBit(command, kPanelRefreshCtrlFrameInsertionAutoModeOffset);
                if (!mFileNode->WriteUint32(kRefreshControlNodeName, command)) {
                    LOG(ERROR) << "VrrController: write file node error, command = " << command;
                }
                dropEventLocked(VrrControllerEventType::kVendorRenderingTimeout);
                return;
            }
            case HWC_POWER_MODE_OFF:
            case HWC_POWER_MODE_NORMAL: {
                return;
            }
            default: {
                LOG(ERROR) << "VrrController: Unknown power mode = " << powerMode;
                return;
            }
        }
    }
}

void VariableRefreshRateController::postSetPowerMode(int32_t powerMode) {
    ATRACE_CALL();
    LOG(INFO) << "VrrController: postSet power mode to " << powerMode << ", from " << mPowerMode;
    {
        const std::lock_guard<std::mutex> lock(mMutex);
        if (mPowerMode == powerMode) {
            return;
        }
        switch (powerMode) {
            case HWC_POWER_MODE_OFF:
            case HWC_POWER_MODE_DOZE:
            case HWC_POWER_MODE_DOZE_SUSPEND: {
                mState = VrrControllerState::kDisable;
                dropEventLocked(VrrControllerEventType::kGeneralEventMask);
                break;
            }
            case HWC_POWER_MODE_NORMAL: {
                // We should transition from either HWC_POWER_MODE_OFF, HWC_POWER_MODE_DOZE, or
                // HWC_POWER_MODE_DOZE_SUSPEND. At this point, there should be no pending events
                // posted.
                if (!mEventQueue.mPriorityQueue.empty()) {
                    LOG(WARNING) << "VrrController: there should be no pending event when resume "
                                    "from power mode = "
                                 << mPowerMode << " to power mode = " << powerMode;
                    LOG(INFO) << dumpEventQueueLocked();
                }
                mState = VrrControllerState::kRendering;
                const auto& vrrConfig = mVrrConfigs[mVrrActiveConfig];
                if (vrrConfig.isFullySupported) {
                    postEvent(VrrControllerEventType::kSystemRenderingTimeout,
                              getSteadyClockTimeNs() +
                                      vrrConfig.notifyExpectedPresentConfig->TimeoutNs);
                }
                break;
            }
            default: {
                LOG(ERROR) << "VrrController: Unknown power mode = " << powerMode;
                return;
            }
        }
        if (!mPowerModeListeners.empty()) {
            for (const auto& listener : mPowerModeListeners) {
                listener->onPowerStateChange(mPowerMode, powerMode);
            }
        }
        mPowerMode = powerMode;
    }
    mCondition.notify_all();
}

void VariableRefreshRateController::setVrrConfigurations(
        std::unordered_map<hwc2_config_t, VrrConfig_t> configs) {
    ATRACE_CALL();

    std::unordered_map<hwc2_config_t, std::vector<int>> validRefreshRates;
    for (const auto& [id, config] : configs) {
        LOG(INFO) << "VrrController: set Vrr configuration id = " << id;
        if (config.isFullySupported) {
            if (!config.notifyExpectedPresentConfig.has_value()) {
                LOG(ERROR) << "VrrController: full vrr config should have "
                              "notifyExpectedPresentConfig.";
                return;
            }
        }
        validRefreshRates[id] = generateValidRefreshRates(config);
    }

    const std::lock_guard<std::mutex> lock(mMutex);
    mVrrConfigs = std::move(configs);
    mValidRefreshRates = std::move(validRefreshRates);
}

int VariableRefreshRateController::getAmbientLightSensorOutput() const {
    return mDisplayContextProvider->getAmbientLightSensorOutput();
}

BrightnessMode VariableRefreshRateController::getBrightnessMode() const {
    return mDisplayContextProvider->getBrightnessMode();
}

int VariableRefreshRateController::getBrightnessNits() const {
    return mDisplayContextProvider->getBrightnessNits();
}

const char* VariableRefreshRateController::getDisplayFileNodePath() const {
    return mDisplayContextProvider->getDisplayFileNodePath();
}

int VariableRefreshRateController::getEstimatedVideoFrameRate() const {
    return mDisplayContextProvider->getEstimatedVideoFrameRate();
}

OperationSpeedMode VariableRefreshRateController::getOperationSpeedMode() const {
    return mDisplayContextProvider->getOperationSpeedMode();
}

bool VariableRefreshRateController::isProximityThrottlingEnabled() const {
    return mDisplayContextProvider->isProximityThrottlingEnabled();
}

void VariableRefreshRateController::setPresentTimeoutParameters(
        int timeoutNs, const std::vector<std::pair<uint32_t, uint32_t>>& settings) {
    const std::lock_guard<std::mutex> lock(mMutex);

    if (!mPresentTimeoutEventHandler) {
        return;
    }
    if ((timeoutNs >= 0) && (!settings.empty())) {
        auto functor = mPresentTimeoutEventHandler->getHandleFunction();
        mVendorPresentTimeoutOverride = std::make_optional<PresentTimeoutSettings>();
        mVendorPresentTimeoutOverride.value().mTimeoutNs = timeoutNs;
        mVendorPresentTimeoutOverride.value().mFunctor = std::move(functor);
        for (const auto& setting : settings) {
            mVendorPresentTimeoutOverride.value().mSchedule.emplace_back(setting);
        }
    } else {
        mVendorPresentTimeoutOverride = std::nullopt;
    }
}

void VariableRefreshRateController::setPresentTimeoutController(uint32_t controllerType) {
    const std::lock_guard<std::mutex> lock(mMutex);

    PresentTimeoutControllerType newControllerType =
            static_cast<PresentTimeoutControllerType>(controllerType);
    if (newControllerType != mPresentTimeoutController) {
        if (mPresentTimeoutController == PresentTimeoutControllerType::kSoftware) {
            dropEventLocked(VrrControllerEventType::kVendorRenderingTimeout);
        }
        mPresentTimeoutController = newControllerType;
        uint32_t command = getCurrentRefreshControlStateLocked();
        if (newControllerType == PresentTimeoutControllerType::kHardware) {
            setBit(command, kPanelRefreshCtrlFrameInsertionAutoModeOffset);
        } else {
            clearBit(command, kPanelRefreshCtrlFrameInsertionAutoModeOffset);
        }
        if (!mFileNode->WriteUint32(composer::kRefreshControlNodeName, command)) {
            LOG(ERROR) << "VrrController: write file node error, command = " << command;
        }
    }
}

int VariableRefreshRateController::setFixedRefreshRateRange(
        uint32_t minimumRefreshRate, uint64_t minLockTimeForPeakRefreshRate) {
    const std::lock_guard<std::mutex> lock(mMutex);

    // If the new setting is equivalent to the old setting.
    if ((minimumRefreshRate) <= 1 && (mMinimumRefreshRate <= 1)) {
        // When |mMinimumRefreshRate| is 0 or 1, it is normal mode; there's no need to compare
        // |mMaximumRefreshRateTimeoutNs|.
        return NO_ERROR;
    } else {
        if ((minimumRefreshRate == mMinimumRefreshRate) &&
            (mMaximumRefreshRateTimeoutNs == minLockTimeForPeakRefreshRate)) {
            return NO_ERROR;
        }
    }
    uint32_t command = getCurrentRefreshControlStateLocked();
    mMinimumRefreshRate = minimumRefreshRate;
    mMaximumRefreshRateTimeoutNs = minLockTimeForPeakRefreshRate;
    dropEventLocked(VrrControllerEventType::kMinLockTimeForPeakRefreshRate);
    if (isMinimumRefreshRateActive()) {
        dropEventLocked(VrrControllerEventType::kVendorRenderingTimeout);
        // Delegate timeout management to hardware.
        setBit(command, kPanelRefreshCtrlFrameInsertionAutoModeOffset);
        // Configure panel to maintain the minimum refresh rate.
        setBitField(command, minimumRefreshRate, kPanelRefreshCtrlMinimumRefreshRateOffset,
                    kPanelRefreshCtrlMinimumRefreshRateMask);
        // TODO(b/333204544): ensure the correct refresh rate is set when calling
        // setFixedRefreshRate().
        // Inform Statistics to stay at the minimum refresh rate change.
        if (mVariableRefreshRateStatistic) {
            mVariableRefreshRateStatistic->setFixedRefreshRate(mMinimumRefreshRate);
        }
        mMinimumRefreshRatePresentStates = kAtMinimumRefreshRate;
        if (mMaximumRefreshRateTimeoutNs > 0) {
            // Set up peak refresh rate timeout event accordingly.
            mMinimumRefreshRateTimeoutEvent =
                    std::make_optional<TimedEvent>("MinimumRefreshRateTimeout");
            mMinimumRefreshRateTimeoutEvent->mFunctor = [this]() -> int {
                if (mMinimumRefreshRatePresentStates == kAtMaximumRefreshRate) {
                    mMinimumRefreshRatePresentStates = kTransitionToMinimumRefreshRate;
                    mMinimumRefreshRateTimeoutEvent->mIsRelativeTime = false;
                    auto delayNs =
                            (std::nano::den / mMinimumRefreshRate) + kMillisecondToNanoSecond;
                    mMinimumRefreshRateTimeoutEvent->mWhenNs = getSteadyClockTimeNs() + delayNs;
                    postEvent(VrrControllerEventType::kMinLockTimeForPeakRefreshRate,
                              mMinimumRefreshRateTimeoutEvent.value());
                    return 1;
                } else {
                    if (mMinimumRefreshRatePresentStates != kTransitionToMinimumRefreshRate) {
                        LOG(ERROR) << "VrrController: expect mMinimumRefreshRatePresentStates is "
                                      "kTransitionToMinimumRefreshRate, but it is "
                                   << mMinimumRefreshRatePresentStates;
                        return -1;
                    }
                    mMinimumRefreshRatePresentStates = kAtMinimumRefreshRate;
                    // TODO(b/333204544): ensure the correct refresh rate is set when calling
                    // setFixedRefreshRate().
                    if (mVariableRefreshRateStatistic) {
                        mVariableRefreshRateStatistic->setFixedRefreshRate(mMinimumRefreshRate);
                    }
                    uint32_t command = getCurrentRefreshControlStateLocked();
                    setBit(command, kPanelRefreshCtrlFrameInsertionAutoModeOffset);
                    setBitField(command, mMinimumRefreshRate,
                                kPanelRefreshCtrlMinimumRefreshRateOffset,
                                kPanelRefreshCtrlMinimumRefreshRateMask);
                    onRefreshRateChangedInternal(mMinimumRefreshRate);
                    return mFileNode->WriteUint32(composer::kRefreshControlNodeName, command);
                }
            };
        }
        if (!mFileNode->WriteUint32(composer::kRefreshControlNodeName, command)) {
            return -1;
        }
        // Report refresh rate change.
        onRefreshRateChangedInternal(mMinimumRefreshRate);
    } else {
        clearBit(command, kPanelRefreshCtrlFrameInsertionAutoModeOffset);
        // Configure panel with the minimum refresh rate = 1.
        setBitField(command, 1, kPanelRefreshCtrlMinimumRefreshRateOffset,
                    kPanelRefreshCtrlMinimumRefreshRateMask);
        // Inform Statistics about the minimum refresh rate change.
        if (!mFileNode->WriteUint32(composer::kRefreshControlNodeName, command)) {
            return -1;
        }
        // TODO(b/333204544): ensure the correct refresh rate is set when calling
        // setFixedRefreshRate().
        if (mVariableRefreshRateStatistic) {
            mVariableRefreshRateStatistic->setFixedRefreshRate(0);
        }
        mMaximumRefreshRateTimeoutNs = 0;
        onRefreshRateChangedInternal(1);
        mMinimumRefreshRateTimeoutEvent = std::nullopt;
        mMinimumRefreshRatePresentStates = kMinRefreshRateUnset;
    }
    return 1;
}

void VariableRefreshRateController::stopThread(bool exit) {
    ATRACE_CALL();
    {
        const std::lock_guard<std::mutex> lock(mMutex);
        mThreadExit = exit;
        mEnabled = false;
        mState = VrrControllerState::kDisable;
    }
    mCondition.notify_all();
}

void VariableRefreshRateController::onPresent(int fence) {
    if (fence < 0) {
        return;
    }
    ATRACE_CALL();
    {
        const std::lock_guard<std::mutex> lock(mMutex);
        if (!mRecord.mPendingCurrentPresentTime.has_value()) {
            LOG(WARNING) << "VrrController: VrrController: Present without expected present time "
                            "information";
            return;
        } else {
            if (mRefreshRateCalculator) {
                mRefreshRateCalculator->onPresent(mRecord.mPendingCurrentPresentTime.value().mTime,
                                                  getPresentFrameFlag());
            }
            if (mFrameRateReporter) {
                mFrameRateReporter->onPresent(mRecord.mPendingCurrentPresentTime.value().mTime, 0);
            }
            if (mVariableRefreshRateStatistic) {
                mVariableRefreshRateStatistic
                        ->onPresent(mRecord.mPendingCurrentPresentTime.value().mTime,
                                    getPresentFrameFlag());
            }
            mRecord.mPresentHistory.next() = mRecord.mPendingCurrentPresentTime.value();
        }
        if (mState == VrrControllerState::kDisable) {
            return;
        } else if (mState == VrrControllerState::kHibernate) {
            LOG(WARNING) << "VrrController: Present during hibernation without prior notification "
                            "via notifyExpectedPresent.";
            mState = VrrControllerState::kRendering;
            dropEventLocked(VrrControllerEventType::kHibernateTimeout);
        }

        if ((mMaximumRefreshRateTimeoutNs > 0) && (mMinimumRefreshRate > 1)) {
            auto maxFrameRate = durationNsToFreq(mVrrConfigs[mVrrActiveConfig].minFrameIntervalNs);
            // If the target minimum refresh rate equals the maxFrameRate, there's no need to
            // promote the refresh rate to maxFrameRate during presentation.
            // E.g. in low-light conditions, with |maxFrameRate| and |mMinimumRefreshRate| both at
            // 120, no refresh rate promotion is needed.
            if (maxFrameRate != mMinimumRefreshRate) {
                if (mMinimumRefreshRatePresentStates == kAtMinimumRefreshRate) {
                    uint32_t command = getCurrentRefreshControlStateLocked();
                    // Delegate timeout management to hardware.
                    setBit(command, kPanelRefreshCtrlFrameInsertionAutoModeOffset);
                    // Configure panel to maintain the minimum refresh rate.
                    setBitField(command, maxFrameRate, kPanelRefreshCtrlMinimumRefreshRateOffset,
                                kPanelRefreshCtrlMinimumRefreshRateMask);
                    if (!mFileNode->WriteUint32(composer::kRefreshControlNodeName, command)) {
                        LOG(WARNING)
                                << "VrrController: write file node error, command = " << command;
                        return;
                    }
                    mMinimumRefreshRatePresentStates = kAtMaximumRefreshRate;
                    onRefreshRateChangedInternal(maxFrameRate);
                    mMinimumRefreshRateTimeoutEvent->mIsRelativeTime = false;
                    mMinimumRefreshRateTimeoutEvent->mWhenNs =
                            mRecord.mPendingCurrentPresentTime.value().mTime +
                            mMaximumRefreshRateTimeoutNs;
                    postEvent(VrrControllerEventType::kMinLockTimeForPeakRefreshRate,
                              mMinimumRefreshRateTimeoutEvent.value());
                } else if (mMinimumRefreshRatePresentStates == kTransitionToMinimumRefreshRate) {
                    dropEventLocked(VrrControllerEventType::kMinLockTimeForPeakRefreshRate);
                    mMinimumRefreshRateTimeoutEvent->mIsRelativeTime = false;
                    auto delayNs =
                            (std::nano::den / mMinimumRefreshRate) + kMillisecondToNanoSecond;
                    mMinimumRefreshRateTimeoutEvent->mWhenNs =
                            mRecord.mPendingCurrentPresentTime.value().mTime + delayNs;
                    postEvent(VrrControllerEventType::kMinLockTimeForPeakRefreshRate,
                              mMinimumRefreshRateTimeoutEvent.value());
                } else {
                    if (mMinimumRefreshRatePresentStates != kAtMaximumRefreshRate) {
                        LOG(ERROR) << "VrrController: wrong state when setting min refresh rate: "
                                   << mMinimumRefreshRatePresentStates;
                    }
                }
            }
            return;
        }
    }

    // Prior to pushing the most recent fence update, verify the release timestamps of all preceding
    // fences.
    // TODO(b/309873055): delegate the task of executing updateVsyncHistory to the Vrr controller's
    // loop thread in order to reduce the workload of calling thread.
    updateVsyncHistory();
    int dupFence = dup(fence);
    if (dupFence < 0) {
        LOG(ERROR) << "VrrController: duplicate fence file failed." << errno;
    }

    {
        const std::lock_guard<std::mutex> lock(mMutex);
        if (mLastPresentFence.has_value()) {
            LOG(WARNING) << "VrrController: last present fence remains open.";
        }
        mLastPresentFence = dupFence;
        // Drop the out of date timeout.
        dropEventLocked(VrrControllerEventType::kSystemRenderingTimeout);
        cancelPresentTimeoutHandlingLocked();
        // Post next rendering timeout.
        int64_t timeoutNs;
        if (mVrrConfigs[mVrrActiveConfig].isFullySupported) {
            timeoutNs = getSteadyClockTimeNs() +
                    mVrrConfigs[mVrrActiveConfig].notifyExpectedPresentConfig->TimeoutNs;
        } else {
            timeoutNs = kDefaultSystemPresentTimeoutNs;
        }
        postEvent(VrrControllerEventType::kSystemRenderingTimeout,
                  getSteadyClockTimeNs() + timeoutNs);
        if (shouldHandleVendorRenderingTimeout()) {
            auto presentTimeoutNs = mVendorPresentTimeoutOverride
                    ? mVendorPresentTimeoutOverride.value().mTimeoutNs
                    : mPresentTimeoutEventHandler->getPresentTimeoutNs();
            // If |presentTimeoutNs| == 0, we don't need to handle the present timeout. Otherwise,
            // post the next frame insertion event
            if (presentTimeoutNs) {
                // Convert the relative time clock from now to the absolute steady time clock.
                presentTimeoutNs = getSteadyClockTimeNs() + presentTimeoutNs;
                postEvent(VrrControllerEventType::kVendorRenderingTimeout, presentTimeoutNs);
            }
        }
        mRecord.mPendingCurrentPresentTime = std::nullopt;
    }
    mCondition.notify_all();
}

void VariableRefreshRateController::setExpectedPresentTime(int64_t timestampNanos,
                                                           int frameIntervalNs) {
    ATRACE_CALL();

    const std::lock_guard<std::mutex> lock(mMutex);
    mRecord.mPendingCurrentPresentTime = {mVrrActiveConfig, timestampNanos, frameIntervalNs};
}

void VariableRefreshRateController::onVsync(int64_t timestampNanos,
                                            int32_t __unused vsyncPeriodNanos) {
    const std::lock_guard<std::mutex> lock(mMutex);
    mRecord.mVsyncHistory
            .next() = {.mType = VariableRefreshRateController::VsyncEvent::Type::kVblank,
                       .mTime = timestampNanos};
}

void VariableRefreshRateController::cancelPresentTimeoutHandlingLocked() {
    dropEventLocked(VrrControllerEventType::kVendorRenderingTimeout);
    dropEventLocked(VrrControllerEventType::kHandleVendorRenderingTimeout);
}

void VariableRefreshRateController::dropEventLocked() {
    mEventQueue.mPriorityQueue = std::priority_queue<VrrControllerEvent>();
}

void VariableRefreshRateController::dropEventLocked(VrrControllerEventType eventType) {
    std::priority_queue<VrrControllerEvent> q;
    auto target = static_cast<int>(eventType);
    while (!mEventQueue.mPriorityQueue.empty()) {
        const auto& it = mEventQueue.mPriorityQueue.top();
        if ((static_cast<int>(it.mEventType) & target) != target) {
            q.push(it);
        }
        mEventQueue.mPriorityQueue.pop();
    }
    mEventQueue.mPriorityQueue = std::move(q);
}

std::string VariableRefreshRateController::dumpEventQueueLocked() {
    std::string content;
    if (mEventQueue.mPriorityQueue.empty()) {
        return content;
    }

    std::priority_queue<VrrControllerEvent> q;
    while (!mEventQueue.mPriorityQueue.empty()) {
        const auto& it = mEventQueue.mPriorityQueue.top();
        content += "VrrController: event = ";
        content += it.toString();
        content += "\n";
        q.push(it);
        mEventQueue.mPriorityQueue.pop();
    }
    mEventQueue.mPriorityQueue = std::move(q);
    return content;
}

uint32_t VariableRefreshRateController::getCurrentRefreshControlStateLocked() const {
    return (mFileNode->getLastWrittenValue(kRefreshControlNodeName) &
            kPanelRefreshCtrlStateBitsMask);
}

int64_t VariableRefreshRateController::getLastFenceSignalTimeUnlocked(int fd) {
    if (fd == -1) {
        return SIGNAL_TIME_INVALID;
    }
    struct sync_file_info* finfo = sync_file_info(fd);
    if (finfo == nullptr) {
        LOG(ERROR) << "VrrController: sync_file_info returned NULL for fd " << fd;
        return SIGNAL_TIME_INVALID;
    }
    if (finfo->status != 1) {
        const auto status = finfo->status;
        if (status < 0) {
            LOG(ERROR) << "VrrController: sync_file_info contains an error: " << status;
        }
        sync_file_info_free(finfo);
        return status < 0 ? SIGNAL_TIME_INVALID : SIGNAL_TIME_PENDING;
    }
    uint64_t timestamp = 0;
    struct sync_fence_info* pinfo = sync_get_fence_info(finfo);
    if (finfo->num_fences != 1) {
        LOG(WARNING) << "VrrController:: there is more than one fence in the file descriptor = "
                     << fd;
    }
    for (size_t i = 0; i < finfo->num_fences; i++) {
        if (pinfo[i].timestamp_ns > timestamp) {
            timestamp = pinfo[i].timestamp_ns;
        }
    }
    sync_file_info_free(finfo);
    return timestamp;
}

int64_t VariableRefreshRateController::getNextEventTimeLocked() const {
    if (mEventQueue.mPriorityQueue.empty()) {
        LOG(WARNING) << "VrrController: event queue should NOT be empty.";
        return -1;
    }
    const auto& event = mEventQueue.mPriorityQueue.top();
    return event.mWhenNs;
}

std::string VariableRefreshRateController::getStateName(VrrControllerState state) const {
    switch (state) {
        case VrrControllerState::kDisable:
            return "Disable";
        case VrrControllerState::kRendering:
            return "Rendering";
        case VrrControllerState::kHibernate:
            return "Hibernate";
        default:
            return "Unknown";
    }
}

void VariableRefreshRateController::handleCadenceChange() {
    ATRACE_CALL();
    if (!mRecord.mNextExpectedPresentTime.has_value()) {
        LOG(WARNING) << "VrrController: cadence change occurs without the expected present timing "
                        "information.";
        return;
    }
    // TODO(b/305311056): handle frame rate change.
    mRecord.mNextExpectedPresentTime = std::nullopt;
}

void VariableRefreshRateController::handleResume() {
    ATRACE_CALL();
    if (!mRecord.mNextExpectedPresentTime.has_value()) {
        LOG(WARNING)
                << "VrrController: resume occurs without the expected present timing information.";
        return;
    }
    // TODO(b/305311281): handle panel resume.
    mRecord.mNextExpectedPresentTime = std::nullopt;
}

void VariableRefreshRateController::handleHibernate() {
    ATRACE_CALL();
    if (mFrameRateReporter) {
        mFrameRateReporter->reset();
    }
    // TODO(b/305311206): handle entering panel hibernate.
    postEvent(VrrControllerEventType::kHibernateTimeout,
              getSteadyClockTimeNs() + kDefaultWakeUpTimeInPowerSaving);
}

void VariableRefreshRateController::handleStayHibernate() {
    ATRACE_CALL();
    // TODO(b/305311698): handle keeping panel hibernate.
    postEvent(VrrControllerEventType::kHibernateTimeout,
              getSteadyClockTimeNs() + kDefaultWakeUpTimeInPowerSaving);
}

void VariableRefreshRateController::handlePresentTimeout(const VrrControllerEvent& event) {
    ATRACE_CALL();

    if (mState == VrrControllerState::kDisable) {
        cancelPresentTimeoutHandlingLocked();
        return;
    }
    uint32_t command = mFileNode->getLastWrittenValue(composer::kRefreshControlNodeName);
    clearBit(command, kPanelRefreshCtrlFrameInsertionAutoModeOffset);
    setBitField(command, 1, kPanelRefreshCtrlFrameInsertionFrameCountOffset,
                kPanelRefreshCtrlFrameInsertionFrameCountMask);
    mFileNode->WriteUint32(composer::kRefreshControlNodeName, command);
    if (mFrameRateReporter) {
        mFrameRateReporter->onPresent(getSteadyClockTimeNs(), 0);
    }
}

void VariableRefreshRateController::onFrameRateChangedForDBI(int refreshRate) {
    // By default, if the refresh rate calculator cannot lock onto a specific frame rate, it may
    // return -1 to reflect this. To avoid reporting a negative frame frequency, return 1 instead in
    // this case.
    auto maxFrameRate = durationNsToFreq(mVrrConfigs[mVrrActiveConfig].minFrameIntervalNs);
    refreshRate = std::max(1, refreshRate);
    refreshRate = std::min(maxFrameRate, refreshRate);
    mFileNode->WriteUint32(kFrameRateNodeName, refreshRate);
}

void VariableRefreshRateController::onRefreshRateChanged(int refreshRate) {
    if (mMinimumRefreshRate > 1) {
        // If the minimum refresh rate has been set, the refresh rate remains fixed at a specific
        // value.
        return;
    }
    onRefreshRateChangedInternal(refreshRate);
}

void VariableRefreshRateController::onRefreshRateChangedInternal(int refreshRate) {
    if (!(mDisplay) || !(mDisplay->mDevice)) {
        LOG(ERROR) << "VrrController: absence of a device or display.";
        return;
    }
    refreshRate =
            refreshRate == kDefaultInvalidRefreshRate ? kDefaultMinimumRefreshRate : refreshRate;
    refreshRate = convertToValidRefreshRate(refreshRate);
    if (mLastRefreshRate == refreshRate) {
        return;
    }
    mLastRefreshRate = refreshRate;
    for (const auto& listener : mRefreshRateChangeListeners) {
        if (listener) listener->onRefreshRateChange(refreshRate);
    }
    reportRefreshRateIndicator();
}

void VariableRefreshRateController::reportRefreshRateIndicator() {
    if (mRefreshRateCalculatorEnabled) {
        if (!mDisplay->mDevice->isVrrApiSupported()) {
            // For legacy API, vsyncPeriodNanos is utilized to denote the refresh rate,
            // refreshPeriodNanos is disregarded.
            mDisplay->mDevice->onRefreshRateChangedDebug(mDisplay->mDisplayId,
                                                         freqToDurationNs(mLastRefreshRate));
        } else {
            mDisplay->mDevice
                    ->onRefreshRateChangedDebug(mDisplay->mDisplayId,
                                                mVrrConfigs[mVrrActiveConfig].vsyncPeriodNs,
                                                freqToDurationNs(mLastRefreshRate));
        }
    }
}

std::vector<int> VariableRefreshRateController::generateValidRefreshRates(
        const VrrConfig_t& config) const {
    std::vector<int> refreshRates;
    int teFrequency = durationNsToFreq(config.vsyncPeriodNs);
    int minVsyncNum = roundDivide(config.minFrameIntervalNs, config.vsyncPeriodNs);
    for (int vsyncNum = minVsyncNum; vsyncNum <= teFrequency; vsyncNum++) {
        refreshRates.push_back(roundDivide(teFrequency, vsyncNum));
    }
    std::set<int> uniqueRefreshRates(refreshRates.begin(), refreshRates.end());
    refreshRates.assign(uniqueRefreshRates.begin(), uniqueRefreshRates.end());
    return refreshRates;
}

int VariableRefreshRateController::convertToValidRefreshRate(int refreshRate) {
    const auto& validRefreshRates = mValidRefreshRates[mVrrActiveConfig];
    auto it = std::lower_bound(validRefreshRates.begin(), validRefreshRates.end(), refreshRate);
    if (it != validRefreshRates.end()) {
        return *it;
    }
    LOG(ERROR) << "Could not match to any valid refresh rate: " << refreshRate;
    return durationNsToFreq(mVrrConfigs[mVrrActiveConfig].minFrameIntervalNs);
}

bool VariableRefreshRateController::shouldHandleVendorRenderingTimeout() const {
    return (mPresentTimeoutController == PresentTimeoutControllerType::kSoftware) &&
            ((!mVendorPresentTimeoutOverride) ||
             (mVendorPresentTimeoutOverride.value().mSchedule.size() > 0)) &&
            (mPowerMode == HWC_POWER_MODE_NORMAL);
}

void VariableRefreshRateController::threadBody() {
    struct sched_param param = {.sched_priority = sched_get_priority_max(SCHED_FIFO)};
    if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
        LOG(ERROR) << "VrrController: fail to set scheduler to SCHED_FIFO.";
        return;
    }
    for (;;) {
        bool stateChanged = false;
        {
            std::unique_lock<std::mutex> lock(mMutex);
            if (mThreadExit) break;
            if (!mEnabled) mCondition.wait(lock);
            if (!mEnabled) continue;

            if (mEventQueue.mPriorityQueue.empty()) {
                mCondition.wait(lock);
            }
            int64_t whenNs = getNextEventTimeLocked();
            int64_t nowNs = getSteadyClockTimeNs();
            if (whenNs > nowNs) {
                int64_t delayNs = whenNs - nowNs;
                auto res = mCondition.wait_for(lock, std::chrono::nanoseconds(delayNs));
                if (res != std::cv_status::timeout) {
                    continue;
                }
            }

            if (mEventQueue.mPriorityQueue.empty()) {
                continue;
            }

            auto event = mEventQueue.mPriorityQueue.top();
            if (event.mWhenNs > getSteadyClockTimeNs()) {
                continue;
            }
            mEventQueue.mPriorityQueue.pop();
            if (static_cast<int>(event.mEventType) &
                static_cast<int>(VrrControllerEventType::kCallbackEventMask)) {
                handleCallbackEventLocked(event);
                continue;
            }
            if (mState == VrrControllerState::kRendering) {
                if (event.mEventType == VrrControllerEventType::kHibernateTimeout) {
                    LOG(ERROR) << "VrrController: receiving a hibernate timeout event while in the "
                                  "rendering state.";
                }
                switch (event.mEventType) {
                    case VrrControllerEventType::kSystemRenderingTimeout: {
                        handleHibernate();
                        mState = VrrControllerState::kHibernate;
                        stateChanged = true;
                        break;
                    }
                    case VrrControllerEventType::kNotifyExpectedPresentConfig: {
                        handleCadenceChange();
                        break;
                    }
                    case VrrControllerEventType::kVendorRenderingTimeout: {
                        if (mPresentTimeoutEventHandler) {
                            // Verify whether a present timeout override exists, and if so, execute
                            // it first.
                            if (mVendorPresentTimeoutOverride) {
                                const auto& params = mVendorPresentTimeoutOverride.value();
                                TimedEvent timedEvent("VendorPresentTimeoutOverride");
                                timedEvent.mIsRelativeTime = true;
                                timedEvent.mFunctor = params.mFunctor;
                                int64_t whenFromNowNs = 0;
                                for (int i = 0; i < params.mSchedule.size(); ++i) {
                                    uint32_t intervalNs = params.mSchedule[i].second;
                                    for (int j = 0; j < params.mSchedule[i].first; ++j) {
                                        timedEvent.mWhenNs = whenFromNowNs;
                                        postEvent(VrrControllerEventType::
                                                          kHandleVendorRenderingTimeout,
                                                  timedEvent);
                                        whenFromNowNs += intervalNs;
                                    }
                                }
                            } else {
                                auto handleEvents = mPresentTimeoutEventHandler->getHandleEvents();
                                if (!handleEvents.empty()) {
                                    for (auto& event : handleEvents) {
                                        postEvent(VrrControllerEventType::
                                                          kHandleVendorRenderingTimeout,
                                                  event);
                                    }
                                }
                            }
                        }
                        break;
                    }
                    case VrrControllerEventType::kHandleVendorRenderingTimeout: {
                        handlePresentTimeout(event);
                        if (event.mFunctor) {
                            event.mFunctor();
                        }
                        break;
                    }
                    default: {
                        break;
                    }
                }
            } else {
                if (event.mEventType == VrrControllerEventType::kSystemRenderingTimeout) {
                    LOG(ERROR) << "VrrController: receiving a rendering timeout event while in the "
                                  "hibernate state.";
                }
                if (mState != VrrControllerState::kHibernate) {
                    LOG(ERROR) << "VrrController: expecting to be in hibernate, but instead in "
                                  "state = "
                               << getStateName(mState);
                }
                switch (event.mEventType) {
                    case VrrControllerEventType::kHibernateTimeout: {
                        handleStayHibernate();
                        break;
                    }
                    case VrrControllerEventType::kNotifyExpectedPresentConfig: {
                        handleResume();
                        mState = VrrControllerState::kRendering;
                        stateChanged = true;
                        break;
                    }
                    default: {
                        break;
                    }
                }
            }
        }
        // TODO(b/309873055): implement a handler to serialize all outer function calls to the same
        // thread owned by the VRR controller.
        if (stateChanged) {
            updateVsyncHistory();
        }
    }
}

void VariableRefreshRateController::postEvent(VrrControllerEventType type, int64_t when) {
    VrrControllerEvent event;
    event.mEventType = type;
    event.mWhenNs = when;
    mEventQueue.mPriorityQueue.emplace(event);
}

void VariableRefreshRateController::postEvent(VrrControllerEventType type, TimedEvent& timedEvent) {
    VrrControllerEvent event;
    event.mEventType = type;
    event.mWhenNs = timedEvent.mIsRelativeTime ? (getSteadyClockTimeNs() + timedEvent.mWhenNs)
                                               : timedEvent.mWhenNs;
    event.mFunctor = std::move(timedEvent.mFunctor);
    mEventQueue.mPriorityQueue.emplace(event);
}

void VariableRefreshRateController::updateVsyncHistory() {
    int fence = -1;

    {
        const std::lock_guard<std::mutex> lock(mMutex);
        if (!mLastPresentFence.has_value()) {
            return;
        }
        fence = mLastPresentFence.value();
        mLastPresentFence = std::nullopt;
    }

    // Execute the following logic unlocked to enhance performance.
    int64_t lastSignalTime = getLastFenceSignalTimeUnlocked(fence);
    if (close(fence)) {
        LOG(ERROR) << "VrrController: close fence file failed, errno = " << errno;
        return;
    } else if (lastSignalTime == SIGNAL_TIME_PENDING || lastSignalTime == SIGNAL_TIME_INVALID) {
        return;
    }

    {
        // Acquire the mutex again to store the vsync record.
        const std::lock_guard<std::mutex> lock(mMutex);
        mRecord.mVsyncHistory
                .next() = {.mType = VariableRefreshRateController::VsyncEvent::Type::kReleaseFence,
                           .mTime = lastSignalTime};
    }
}

} // namespace android::hardware::graphics::composer
