void SurfaceFlinger::onMessageRefresh() {
    mRefreshPending = false;

    compositionengine::CompositionRefreshArgs refreshArgs;
    const auto& displays = ON_MAIN_THREAD(mDisplays);
    refreshArgs.outputs.reserve(displays.size());
    for (const auto& [_, display] : displays) {
        refreshArgs.outputs.push_back(display->getCompositionDisplay());
    }
    mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
        if (auto layerFE = layer->getCompositionEngineLayerFE())
            refreshArgs.layers.push_back(layerFE);
    });
    refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
    for (auto layer : mLayersWithQueuedFrames) {
        if (auto layerFE = layer->getCompositionEngineLayerFE())
            refreshArgs.layersWithQueuedFrames.push_back(layerFE);
    }

    refreshArgs.repaintEverything = mRepaintEverything.exchange(false);
    refreshArgs.outputColorSetting = useColorManagement
            ? mDisplayColorSetting
            : compositionengine::OutputColorSetting::kUnmanaged;
    refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace;
    refreshArgs.forceOutputColorMode = mForceColorMode;

    refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
    refreshArgs.updatingGeometryThisFrame = mGeometryInvalid || mVisibleRegionsDirty;
    refreshArgs.blursAreExpensive = mBlursAreExpensive;
    refreshArgs.internalDisplayRotationFlags = DisplayDevice::getPrimaryDisplayRotationFlags();
    if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
        refreshArgs.colorTransformMatrix = mDrawingState.colorMatrix;
        mDrawingState.colorMatrixChanged = false;
    }

    refreshArgs.devOptForceClientComposition = mDebugDisableHWC || mDebugRegion;

    if (mDebugRegion != 0) {
        refreshArgs.devOptFlashDirtyRegionsDelay =
                std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0);
    }

    const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(mExpectedPresentTime);
    const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
    refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
    refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime;
    refreshArgs.nextInvalidateTime = mEventQueue->nextExpectedInvalidate();
    mGeometryInvalid = false;

    // Store the present time just before calling to the composition engine so we could notify
    // the scheduler.
    const auto presentTime = systemTime();

    mCompositionEngine->present(refreshArgs);
    mTimeStats->recordFrameDuration(mFrameStartTime, systemTime());
    // Reset the frame start time now that we've recorded this frame.
    mFrameStartTime = 0;

    mScheduler->onDisplayRefreshed(presentTime);
    postFrame();
    postComposition();
    const bool prevFrameHadClientComposition = mHadClientComposition;

    mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
        const auto& state = pair.second->getCompositionDisplay()->getState();
        return state.usesClientComposition && !state.reusedClientComposition;
    });
    mHadDeviceComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
        const auto& state = pair.second->getCompositionDisplay()->getState();
        return state.usesDeviceComposition;
    });
    mReusedClientComposition =
            std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
                const auto& state = pair.second->getCompositionDisplay()->getState();
                return state.reusedClientComposition;
            });
    // Only report a strategy change if we move in and out of client composition
    if (prevFrameHadClientComposition != mHadClientComposition) {
        mTimeStats->incrementCompositionStrategyChanges();
    }

    // TODO: b/160583065 Enable skip validation when SF caches all client composition layers
    const bool usedGpuComposition = mHadClientComposition || mReusedClientComposition;
    modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
    mLayersWithQueuedFrames.clear();
    if (mTracingEnabled && mTracePostComposition) {
        // This may block if SurfaceTracing is running in sync mode.
        if (mVisibleRegionsDirty) {
            mTracing.notify("visibleRegionsDirty");
        } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) {
            mTracing.notify("bufferLatched");
        }
    }

    mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp
    mVisibleRegionsDirty = false;

    if (mCompositionEngine->needsAnotherUpdate()) {
        signalLayerUpdate();
    }
}