diff options
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 3884 |
1 files changed, 2187 insertions, 1697 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ce793ad9c5..e9fbf6ea7b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -24,8 +24,12 @@ #include "SurfaceFlinger.h" +#include <android-base/parseint.h> #include <android-base/properties.h> +#include <android-base/stringprintf.h> +#include <android-base/strings.h> #include <android/configuration.h> +#include <android/gui/IDisplayEventConnection.h> #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/types.h> @@ -48,10 +52,11 @@ #include <configstore/Utils.h> #include <cutils/compiler.h> #include <cutils/properties.h> +#include <ftl/fake_guard.h> #include <ftl/future.h> +#include <ftl/small_map.h> #include <gui/BufferQueue.h> #include <gui/DebugEGLImageTracker.h> -#include <gui/IDisplayEventConnection.h> #include <gui/IProducerListener.h> #include <gui/LayerDebugInfo.h> #include <gui/LayerMetadata.h> @@ -65,8 +70,10 @@ #include <private/gui/SyncFeatures.h> #include <processgroup/processgroup.h> #include <renderengine/RenderEngine.h> +#include <renderengine/impl/ExternalTexture.h> #include <sys/types.h> #include <ui/ColorSpace.h> +#include <ui/DataspaceUtils.h> #include <ui/DebugUtils.h> #include <ui/DisplayId.h> #include <ui/DisplayMode.h> @@ -88,11 +95,14 @@ #include <cmath> #include <cstdint> #include <functional> +#include <memory> #include <mutex> #include <optional> #include <type_traits> #include <unordered_map> +#include <ui/DisplayIdentification.h> +#include "BackgroundExecutor.h" #include "BufferLayer.h" #include "BufferQueueLayer.h" #include "BufferStateLayer.h" @@ -101,14 +111,15 @@ #include "ContainerLayer.h" #include "DisplayDevice.h" #include "DisplayHardware/ComposerHal.h" -#include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/Hal.h" +#include "DisplayHardware/PowerAdvisor.h" #include "DisplayHardware/VirtualDisplaySurface.h" #include "DisplayRenderArea.h" #include "EffectLayer.h" #include "Effects/Daltonizer.h" +#include "FlagManager.h" #include "FpsReporter.h" #include "FrameTimeline/FrameTimeline.h" #include "FrameTracer/FrameTracer.h" @@ -118,13 +129,13 @@ #include "LayerRenderArea.h" #include "LayerVector.h" #include "MonitoredProducer.h" +#include "MutexUtils.h" #include "NativeWindowSurface.h" #include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" #include "Scheduler/DispSyncSource.h" #include "Scheduler/EventThread.h" #include "Scheduler/LayerHistory.h" -#include "Scheduler/MessageQueue.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncConfiguration.h" #include "Scheduler/VsyncController.h" @@ -134,40 +145,32 @@ #include "TimeStats/TimeStats.h" #include "TunnelModeEnabledReporter.h" #include "WindowInfosListenerInvoker.h" -#include "android-base/parseint.h" -#include "android-base/stringprintf.h" -#include "android-base/strings.h" - -#define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock) - -#define ON_MAIN_THREAD(expr) \ - [&] { \ - LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \ - UnnecessaryLock lock(mStateLock); \ - return (expr); \ - }() - -#define MAIN_THREAD_GUARD(expr) \ - [&] { \ - LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \ - MainThreadScopedGuard lock(SF_MAIN_THREAD); \ - return (expr); \ - }() + +#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h> +#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> +#include <aidl/android/hardware/graphics/composer3/RenderIntent.h> #undef NO_THREAD_SAFETY_ANALYSIS #define NO_THREAD_SAFETY_ANALYSIS \ - _Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"") + _Pragma("GCC error \"Prefer <ftl/fake_guard.h> or MutexUtils.h helpers.\"") namespace android { using namespace std::string_literals; -using namespace android::hardware::configstore; -using namespace android::hardware::configstore::V1_0; -using namespace android::sysprop; +using namespace hardware::configstore; +using namespace hardware::configstore::V1_0; +using namespace sysprop; + +using aidl::android::hardware::graphics::common::DisplayDecorationSupport; +using aidl::android::hardware::graphics::composer3::Capability; +using aidl::android::hardware::graphics::composer3::DisplayCapability; +using CompositionStrategyPredictionState = android::compositionengine::impl:: + OutputCompositionState::CompositionStrategyPredictionState; -using android::hardware::power::Boost; using base::StringAppendF; +using gui::DisplayInfo; +using gui::IDisplayEventConnection; using gui::IWindowInfosListener; using gui::WindowInfo; using ui::ColorMode; @@ -175,6 +178,8 @@ using ui::Dataspace; using ui::DisplayPrimaries; using ui::RenderIntent; +using KernelIdleTimerController = scheduler::RefreshRateConfigs::KernelIdleTimerController; + namespace hal = android::hardware::graphics::composer::hal; namespace { @@ -206,43 +211,6 @@ bool isWideColorMode(const ColorMode colorMode) { #pragma clang diagnostic pop -template <typename Mutex> -struct SCOPED_CAPABILITY ConditionalLockGuard { - ConditionalLockGuard(Mutex& mutex, bool lock) ACQUIRE(mutex) : mutex(mutex), lock(lock) { - if (lock) mutex.lock(); - } - - ~ConditionalLockGuard() RELEASE() { - if (lock) mutex.unlock(); - } - - Mutex& mutex; - const bool lock; -}; - -using ConditionalLock = ConditionalLockGuard<Mutex>; - -struct SCOPED_CAPABILITY TimedLock { - TimedLock(Mutex& mutex, nsecs_t timeout, const char* whence) ACQUIRE(mutex) - : mutex(mutex), status(mutex.timedLock(timeout)) { - ALOGE_IF(!locked(), "%s timed out locking: %s (%d)", whence, strerror(-status), status); - } - - ~TimedLock() RELEASE() { - if (locked()) mutex.unlock(); - } - - bool locked() const { return status == NO_ERROR; } - - Mutex& mutex; - const status_t status; -}; - -struct SCOPED_CAPABILITY UnnecessaryLock { - explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {} - ~UnnecessaryLock() RELEASE() {} -}; - // TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity. constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV; @@ -261,52 +229,33 @@ bool validateCompositionDataspace(Dataspace dataspace) { return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3; } -class FrameRateFlexibilityToken : public BBinder { -public: - FrameRateFlexibilityToken(std::function<void()> callback) : mCallback(callback) {} - virtual ~FrameRateFlexibilityToken() { mCallback(); } - -private: - std::function<void()> mCallback; -}; - -enum Permission { - ACCESS_SURFACE_FLINGER = 0x1, - ROTATE_SURFACE_FLINGER = 0x2, -}; - -struct IdleTimerConfig { - int32_t timeoutMs; - bool supportKernelIdleTimer; -}; - -IdleTimerConfig getIdleTimerConfiguration(DisplayId displayId) { - // TODO(adyabr): use ro.surface_flinger.* namespace - +std::chrono::milliseconds getIdleTimerTimeout(DisplayId displayId) { const auto displayIdleTimerMsKey = [displayId] { std::stringstream ss; ss << "debug.sf.set_idle_timer_ms_" << displayId.value; return ss.str(); }(); + const int32_t displayIdleTimerMs = base::GetIntProperty(displayIdleTimerMsKey, 0); + if (displayIdleTimerMs > 0) { + return std::chrono::milliseconds(displayIdleTimerMs); + } + + const int32_t setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms", 0); + const int32_t millis = setIdleTimerMs ? setIdleTimerMs : sysprop::set_idle_timer_ms(0); + return std::chrono::milliseconds(millis); +} + +bool getKernelIdleTimerSyspropConfig(DisplayId displayId) { const auto displaySupportKernelIdleTimerKey = [displayId] { std::stringstream ss; ss << "debug.sf.support_kernel_idle_timer_" << displayId.value; return ss.str(); }(); - const int32_t displayIdleTimerMs = base::GetIntProperty(displayIdleTimerMsKey, 0); const auto displaySupportKernelIdleTimer = base::GetBoolProperty(displaySupportKernelIdleTimerKey, false); - - if (displayIdleTimerMs > 0) { - return {displayIdleTimerMs, displaySupportKernelIdleTimer}; - } - - const int32_t setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms", 0); - const int32_t millis = setIdleTimerMs ? setIdleTimerMs : sysprop::set_idle_timer_ms(0); - - return {millis, sysprop::support_kernel_idle_timer(false)}; + return displaySupportKernelIdleTimer || sysprop::support_kernel_idle_timer(false); } } // namespace anonymous @@ -320,6 +269,7 @@ const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); const String16 sControlDisplayBrightness("android.permission.CONTROL_DISPLAY_BRIGHTNESS"); const String16 sDump("android.permission.DUMP"); const String16 sCaptureBlackoutContent("android.permission.CAPTURE_BLACKOUT_CONTENT"); +const String16 sInternalSystemWindow("android.permission.INTERNAL_SYSTEM_WINDOW"); const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled"; @@ -331,16 +281,12 @@ int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; uint32_t SurfaceFlinger::maxGraphicsWidth; uint32_t SurfaceFlinger::maxGraphicsHeight; bool SurfaceFlinger::hasWideColorDisplay; -ui::Rotation SurfaceFlinger::internalDisplayOrientation = ui::ROTATION_0; -bool SurfaceFlinger::useColorManagement; bool SurfaceFlinger::useContextPriority; Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888; Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; -bool SurfaceFlinger::useFrameRateApi; -bool SurfaceFlinger::enableSdrDimming; -bool SurfaceFlinger::enableLatchUnsignaled; +LatchUnsignaledConfig SurfaceFlinger::enableLatchUnsignaledConfig; std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { switch(displayColorSetting) { @@ -364,20 +310,28 @@ bool callingThreadHasRotateSurfaceFlingerAccess() { PermissionCache::checkPermission(sRotateSurfaceFlinger, pid, uid); } +bool callingThreadHasInternalSystemWindowAccess() { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + return uid == AID_GRAPHICS || uid == AID_SYSTEM || + PermissionCache::checkPermission(sInternalSystemWindow, pid, uid); +} + SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) : mFactory(factory), + mPid(getpid()), mInterceptor(mFactory.createSurfaceInterceptor()), mTimeStats(std::make_shared<impl::TimeStats>()), mFrameTracer(mFactory.createFrameTracer()), - mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())), - mEventQueue(mFactory.createMessageQueue()), + mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)), mCompositionEngine(mFactory.createCompositionEngine()), mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)), mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()), mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)), mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)), - mPowerAdvisor(*this), - mWindowInfosListenerInvoker(new WindowInfosListenerInvoker(this)) { + mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)), + mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) { ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); } @@ -396,11 +350,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI maxGraphicsHeight = std::max(max_graphics_height(0), 0); hasWideColorDisplay = has_wide_color_display(false); - - // Android 12 and beyond, color management in display pipeline is turned on - // by default. - useColorManagement = use_color_management(true); - mDefaultCompositionDataspace = static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB)); mWideColorGamutCompositionDataspace = static_cast<ui::Dataspace>(wcg_composition_dataspace( @@ -423,22 +372,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI useContextPriority = use_context_priority(true); - using Values = SurfaceFlingerProperties::primary_display_orientation_values; - switch (primary_display_orientation(Values::ORIENTATION_0)) { - case Values::ORIENTATION_0: - break; - case Values::ORIENTATION_90: - internalDisplayOrientation = ui::ROTATION_90; - break; - case Values::ORIENTATION_180: - internalDisplayOrientation = ui::ROTATION_180; - break; - case Values::ORIENTATION_270: - internalDisplayOrientation = ui::ROTATION_270; - break; - } - ALOGV("Internal Display Orientation: %s", toCString(internalDisplayOrientation)); - mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries(); // debugging stuff... @@ -450,10 +383,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("ro.build.type", value, "user"); mIsUserBuild = strcmp(value, "user") == 0; - property_get("debug.sf.showupdates", value, "0"); - mDebugRegion = atoi(value); - - ALOGI_IF(mDebugRegion, "showupdates enabled"); + mDebugFlashDelay = base::GetUintProperty("debug.sf.showupdates"s, 0u); // DDMS debugging deprecated (b/120782499) property_get("debug.sf.ddms", value, "0"); @@ -486,6 +416,12 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("debug.sf.disable_client_composition_cache", value, "0"); mDisableClientCompositionCache = atoi(value); + property_get("debug.sf.predict_hwc_composition_strategy", value, "1"); + mPredictCompositionStrategy = atoi(value); + + property_get("debug.sf.treat_170m_as_sRGB", value, "0"); + mTreat170mAsSrgb = atoi(value); + // We should be reading 'persist.sys.sf.color_saturation' here // but since /data may be encrypted, we need to wait until after vold // comes online to attempt to read the property. The property is @@ -501,28 +437,35 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI android::hardware::details::setTrebleTestingOverride(true); } - useFrameRateApi = use_frame_rate_api(true); - mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0); - // Debug property overrides ro. property - enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false)); + if (!mIsUserBuild && base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, true)) { + mTransactionTracing.emplace(); + } - enableLatchUnsignaled = base::GetBoolProperty("debug.sf.latch_unsignaled"s, false); + mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); } -SurfaceFlinger::~SurfaceFlinger() = default; +LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { + if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) { + return LatchUnsignaledConfig::Always; + } -void SurfaceFlinger::onFirstRef() { - mEventQueue->init(this); + if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, true)) { + return LatchUnsignaledConfig::AutoSingleLayer; + } + + return LatchUnsignaledConfig::Disabled; } +SurfaceFlinger::~SurfaceFlinger() = default; + void SurfaceFlinger::binderDied(const wp<IBinder>&) { // the window manager died on us. prepare its eulogy. mBootFinished = false; - // Sever the link to inputflinger since its gone as well. - static_cast<void>(schedule([=] { mInputFlinger = nullptr; })); + // Sever the link to inputflinger since it's gone as well. + static_cast<void>(mScheduler->schedule([=] { mInputFlinger = nullptr; })); // restore initial conditions (default device unblank, etc) initializeDisplays(); @@ -532,16 +475,7 @@ void SurfaceFlinger::binderDied(const wp<IBinder>&) { } void SurfaceFlinger::run() { - while (true) { - mEventQueue->waitMessage(); - } -} - -template <typename F, typename T> -inline std::future<T> SurfaceFlinger::schedule(F&& f) { - auto [task, future] = makeTask(std::move(f)); - mEventQueue->postMessage(std::move(task)); - return std::move(future); + mScheduler->run(); } sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() { @@ -590,13 +524,13 @@ void SurfaceFlinger::destroyDisplay(const sp<IBinder>& displayToken) { const ssize_t index = mCurrentState.displays.indexOfKey(displayToken); if (index < 0) { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", __func__, displayToken.get()); return; } const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); if (state.physical) { - ALOGE("%s: Invalid operation on physical display", __FUNCTION__); + ALOGE("%s: Invalid operation on physical display", __func__); return; } mInterceptor->saveDisplayDeletion(state.sequenceId); @@ -650,17 +584,14 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { } std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const { - const auto display = getDefaultDisplayDeviceLocked(); - if (!display) { - return {}; - } - std::vector<PhysicalDisplayId> displayIds; displayIds.reserve(mPhysicalDisplayTokens.size()); - displayIds.push_back(display->getPhysicalId()); + + const auto defaultDisplayId = getDefaultDisplayDeviceLocked()->getPhysicalId(); + displayIds.push_back(defaultDisplayId); for (const auto& [id, token] : mPhysicalDisplayTokens) { - if (id != display->getPhysicalId()) { + if (id != defaultDisplayId) { displayIds.push_back(id); } } @@ -670,12 +601,7 @@ std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() con status_t SurfaceFlinger::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) const { Mutex::Autolock lock(mStateLock); - const auto display = getInternalDisplayIdLocked(); - if (!display) { - return NAME_NOT_FOUND; - } - - *id = *display; + *id = getPrimaryDisplayIdLocked(); return NO_ERROR; } @@ -723,6 +649,7 @@ void SurfaceFlinger::bootFinished() { mFrameTracer->initialize(); mFrameTimeline->onBootFinished(); + getRenderEngine().setEnableTracing(mFlagManager.use_skia_tracing()); // wait patiently for the window manager death const String16 name("window"); @@ -742,7 +669,7 @@ void SurfaceFlinger::bootFinished() { sp<IBinder> input(defaultServiceManager()->getService(String16("inputflinger"))); - static_cast<void>(schedule([=] { + static_cast<void>(mScheduler->schedule([=] { if (input == nullptr) { ALOGE("Failed to link to input service"); } else { @@ -750,11 +677,28 @@ void SurfaceFlinger::bootFinished() { } readPersistentProperties(); - mPowerAdvisor.onBootFinished(); + mPowerAdvisor->onBootFinished(); + const bool powerHintEnabled = mFlagManager.use_adpf_cpu_hint(); + mPowerAdvisor->enablePowerHint(powerHintEnabled); + const bool powerHintUsed = mPowerAdvisor->usePowerHintSession(); + ALOGD("Power hint is %s", + powerHintUsed ? "supported" : (powerHintEnabled ? "unsupported" : "disabled")); + if (powerHintUsed) { + std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid(); + std::vector<int32_t> tidList; + tidList.emplace_back(gettid()); + if (renderEngineTid.has_value()) { + tidList.emplace_back(*renderEngineTid); + } + if (!mPowerAdvisor->startPowerHintSession(tidList)) { + ALOGW("Cannot start power hint session"); + } + } + mBootStage = BootStage::FINISHED; if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) { - ON_MAIN_THREAD(enableRefreshRateOverlay(true)); + FTL_FAKE_GUARD(mStateLock, enableRefreshRateOverlay(true)); } })); } @@ -783,7 +727,7 @@ uint32_t SurfaceFlinger::getNewTexture() { if (std::this_thread::get_id() == mMainThreadId) { return genTextures(); } else { - return schedule(genTextures).get(); + return mScheduler->schedule(genTextures).get(); } } @@ -795,6 +739,25 @@ void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { ATRACE_INT("TexturePoolSize", mTexturePool.size()); } +static std::optional<renderengine::RenderEngine::RenderEngineType> +chooseRenderEngineTypeViaSysProp() { + char prop[PROPERTY_VALUE_MAX]; + property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, ""); + + if (strcmp(prop, "gles") == 0) { + return renderengine::RenderEngine::RenderEngineType::GLES; + } else if (strcmp(prop, "threaded") == 0) { + return renderengine::RenderEngine::RenderEngineType::THREADED; + } else if (strcmp(prop, "skiagl") == 0) { + return renderengine::RenderEngine::RenderEngineType::SKIA_GL; + } else if (strcmp(prop, "skiaglthreaded") == 0) { + return renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED; + } else { + ALOGE("Unrecognized RenderEngineType %s; ignoring!", prop); + return {}; + } +} + // Do not call property_set on main thread which will be blocked by init // Use StartPropertySetThread instead. void SurfaceFlinger::init() { @@ -805,19 +768,21 @@ void SurfaceFlinger::init() { // Get a RenderEngine for the given display / config (can't fail) // TODO(b/77156734): We need to stop casting and use HAL types when possible. // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display. - mCompositionEngine->setRenderEngine(renderengine::RenderEngine::create( - renderengine::RenderEngineCreationArgs::Builder() - .setPixelFormat(static_cast<int32_t>(defaultCompositionPixelFormat)) - .setImageCacheSize(maxFrameBufferAcquiredBuffers) - .setUseColorManagerment(useColorManagement) - .setEnableProtectedContext(enable_protected_contents(false)) - .setPrecacheToneMapperShaderOnly(false) - .setSupportsBackgroundBlur(mSupportsBlur) - .setContextPriority( - useContextPriority - ? renderengine::RenderEngine::ContextPriority::REALTIME - : renderengine::RenderEngine::ContextPriority::MEDIUM) - .build())); + auto builder = renderengine::RenderEngineCreationArgs::Builder() + .setPixelFormat(static_cast<int32_t>(defaultCompositionPixelFormat)) + .setImageCacheSize(maxFrameBufferAcquiredBuffers) + .setUseColorManagerment(useColorManagement) + .setEnableProtectedContext(enable_protected_contents(false)) + .setPrecacheToneMapperShaderOnly(false) + .setSupportsBackgroundBlur(mSupportsBlur) + .setContextPriority( + useContextPriority + ? renderengine::RenderEngine::ContextPriority::REALTIME + : renderengine::RenderEngine::ContextPriority::MEDIUM); + if (auto type = chooseRenderEngineTypeViaSysProp()) { + builder.setRenderEngineType(type.value()); + } + mCompositionEngine->setRenderEngine(renderengine::RenderEngine::create(builder.build())); mMaxRenderTargetSize = std::min(getRenderEngine().getMaxTextureSize(), getRenderEngine().getMaxViewportDims()); @@ -828,9 +793,11 @@ void SurfaceFlinger::init() { mCompositionEngine->setTimeStats(mTimeStats); mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName)); - mCompositionEngine->getHwComposer().setCallback(this); + mCompositionEngine->getHwComposer().setCallback(*this); ClientCache::getInstance().setRenderEngine(&getRenderEngine()); + enableLatchUnsignaledConfig = getLatchUnsignaledConfig(); + if (base::GetBoolProperty("debug.sf.enable_hwc_vds"s, false)) { enableHalVirtualDisplays(true); } @@ -838,10 +805,10 @@ void SurfaceFlinger::init() { // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); const auto display = getDefaultDisplayDeviceLocked(); - LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback."); + LOG_ALWAYS_FATAL_IF(!display, "Missing primary display after registering composer callback."); const auto displayId = display->getPhysicalId(); LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId), - "Internal display is disconnected."); + "Primary display is disconnected."); // initialize our drawing state mDrawingState = mCurrentState; @@ -849,7 +816,7 @@ void SurfaceFlinger::init() { // set initial conditions (e.g. unblank default device) initializeDisplays(); - mPowerAdvisor.init(); + mPowerAdvisor->init(); char primeShaderCache[PROPERTY_VALUE_MAX]; property_get("service.sf.prime_shader_cache", primeShaderCache, "1"); @@ -870,7 +837,7 @@ void SurfaceFlinger::init() { // Inform native graphics APIs whether the present timestamp is supported: const bool presentFenceReliable = - !getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE); + !getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE); mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable); if (mStartPropertySetThread->Start() != NO_ERROR) { @@ -916,9 +883,8 @@ bool SurfaceFlinger::authenticateSurfaceTexture( } bool SurfaceFlinger::authenticateSurfaceTextureLocked( - const sp<IGraphicBufferProducer>& bufferProducer) const { - sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer)); - return mGraphicBufferProducerList.count(surfaceTextureBinder.get()) > 0; + const sp<IGraphicBufferProducer>& /* bufferProducer */) const { + return false; } status_t SurfaceFlinger::getSupportedFrameTimestamps( @@ -933,9 +899,10 @@ status_t SurfaceFlinger::getSupportedFrameTimestamps( FrameEvent::DEQUEUE_READY, FrameEvent::RELEASE, }; - ConditionalLock _l(mStateLock, - std::this_thread::get_id() != mMainThreadId); - if (!getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) { + + ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); + + if (!getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) { outSupported->push_back(FrameEvent::DISPLAY_PRESENT); } return NO_ERROR; @@ -993,6 +960,7 @@ status_t SurfaceFlinger::getStaticDisplayInfo(const sp<IBinder>& displayToken, info->secure = display->isSecure(); info->deviceProductInfo = display->getDeviceProductInfo(); + info->installOrientation = display->getPhysicalOrientation(); return NO_ERROR; } @@ -1010,43 +978,40 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, return NAME_NOT_FOUND; } - info->activeDisplayModeId = static_cast<int32_t>(display->getActiveMode()->getId().value()); + const auto displayId = PhysicalDisplayId::tryCast(display->getId()); + if (!displayId) { + return INVALID_OPERATION; + } + + info->activeDisplayModeId = display->getActiveMode()->getId().value(); const auto& supportedModes = display->getSupportedModes(); info->supportedDisplayModes.clear(); info->supportedDisplayModes.reserve(supportedModes.size()); - for (const auto& mode : supportedModes) { - ui::DisplayMode outMode; - outMode.id = static_cast<int32_t>(mode->getId().value()); - auto width = mode->getWidth(); - auto height = mode->getHeight(); + for (const auto& [id, mode] : supportedModes) { + ui::DisplayMode outMode; + outMode.id = static_cast<int32_t>(id.value()); - auto xDpi = mode->getDpiX(); - auto yDpi = mode->getDpiY(); + auto [width, height] = mode->getResolution(); + auto [xDpi, yDpi] = mode->getDpi(); - if (display->isPrimary() && - (internalDisplayOrientation == ui::ROTATION_90 || - internalDisplayOrientation == ui::ROTATION_270)) { + if (const auto physicalOrientation = display->getPhysicalOrientation(); + physicalOrientation == ui::ROTATION_90 || physicalOrientation == ui::ROTATION_270) { std::swap(width, height); std::swap(xDpi, yDpi); } outMode.resolution = ui::Size(width, height); - if (mEmulatedDisplayDensity) { - outMode.xDpi = mEmulatedDisplayDensity; - outMode.yDpi = mEmulatedDisplayDensity; - } else { - outMode.xDpi = xDpi; - outMode.yDpi = yDpi; - } + outMode.xDpi = xDpi; + outMode.yDpi = yDpi; const nsecs_t period = mode->getVsyncPeriod(); outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue(); const auto vsyncConfigSet = - mVsyncConfiguration->getConfigsForRefreshRate(Fps(outMode.refreshRate)); + mVsyncConfiguration->getConfigsForRefreshRate(Fps::fromValue(outMode.refreshRate)); outMode.appVsyncOffset = vsyncConfigSet.late.appOffset; outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset; outMode.group = mode->getGroup(); @@ -1069,18 +1034,25 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, } info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; - const auto displayId = display->getPhysicalId(); - info->supportedColorModes = getDisplayColorModes(displayId); - + info->supportedColorModes = getDisplayColorModes(*display); info->hdrCapabilities = display->getHdrCapabilities(); + info->autoLowLatencyModeSupported = - getHwComposer().hasDisplayCapability(displayId, - hal::DisplayCapability::AUTO_LOW_LATENCY_MODE); - std::vector<hal::ContentType> types; - getHwComposer().getSupportedContentTypes(displayId, &types); - info->gameContentTypeSupported = std::any_of(types.begin(), types.end(), [](auto type) { - return type == hal::ContentType::GAME; - }); + getHwComposer().hasDisplayCapability(*displayId, + DisplayCapability::AUTO_LOW_LATENCY_MODE); + info->gameContentTypeSupported = + getHwComposer().supportsContentType(*displayId, hal::ContentType::GAME); + + info->preferredBootDisplayMode = static_cast<ui::DisplayModeId>(-1); + + if (getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG)) { + if (const auto hwcId = getHwComposer().getPreferredBootDisplayMode(*displayId)) { + if (const auto modeId = display->translateModeId(*hwcId)) { + info->preferredBootDisplayMode = modeId->value(); + } + } + } + return NO_ERROR; } @@ -1107,11 +1079,11 @@ void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { } if (display->setDesiredActiveMode(info)) { - // This will trigger HWC refresh without resetting the idle timer. - repaintEverythingForHWC(); + scheduleComposite(FrameHint::kNone); + // Start receiving vsync samples now, so that we can detect a period // switch. - mScheduler->resyncToHardwareVsync(true, info.mode->getVsyncPeriod()); + mScheduler->resyncToHardwareVsync(true, info.mode->getFps()); // As we called to set period, we will call to onRefreshRateChangeCompleted once // VsyncController model is locked. modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated); @@ -1121,15 +1093,15 @@ void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { } } -status_t SurfaceFlinger::setActiveMode(const sp<IBinder>& displayToken, int modeId) { +status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<IBinder>& displayToken, int modeId) { ATRACE_CALL(); if (!displayToken) { return BAD_VALUE; } - auto future = schedule([=]() -> status_t { - const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken)); + auto future = mScheduler->schedule([=]() -> status_t { + const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken)); if (!display) { ALOGE("Attempt to set allowed display modes for invalid display token %p", displayToken.get()); @@ -1162,7 +1134,7 @@ status_t SurfaceFlinger::setActiveMode(const sp<IBinder>& displayToken, int mode return future.get(); } -void SurfaceFlinger::setActiveModeInternal() { +void SurfaceFlinger::updateInternalStateWithChangedMode() { ATRACE_CALL(); const auto display = getDefaultDisplayDeviceLocked(); @@ -1170,14 +1142,16 @@ void SurfaceFlinger::setActiveModeInternal() { return; } - const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode()); + const auto upcomingModeInfo = + FTL_FAKE_GUARD(kMainThreadContext, display->getUpcomingActiveMode()); + if (!upcomingModeInfo.mode) { // There is no pending mode change. This can happen if the active // display changed and the mode change happened on a different display. return; } - if (display->getActiveMode()->getSize() != upcomingModeInfo.mode->getSize()) { + if (display->getActiveMode()->getResolution() != upcomingModeInfo.mode->getResolution()) { auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken()); // We need to generate new sequenceId in order to recreate the display (and this // way the framebuffer). @@ -1189,16 +1163,15 @@ void SurfaceFlinger::setActiveModeInternal() { return; } - // We just created this display so we can call even if we are not on - // the main thread - MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + // We just created this display so we can call even if we are not on the main thread. + ftl::FakeGuard guard(kMainThreadContext); display->setActiveMode(upcomingModeInfo.mode->getId()); const Fps refreshRate = upcomingModeInfo.mode->getFps(); mRefreshRateStats->setRefreshRate(refreshRate); updatePhaseConfiguration(refreshRate); - if (upcomingModeInfo.event != Scheduler::ModeEvent::None) { + if (upcomingModeInfo.event != DisplayModeEvent::None) { mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode); } } @@ -1213,13 +1186,14 @@ void SurfaceFlinger::clearDesiredActiveModeState(const sp<DisplayDevice>& displa void SurfaceFlinger::desiredActiveModeChangeDone(const sp<DisplayDevice>& display) { const auto refreshRate = display->getDesiredActiveMode()->mode->getFps(); clearDesiredActiveModeState(display); - mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs()); + mScheduler->resyncToHardwareVsync(true, refreshRate); updatePhaseConfiguration(refreshRate); } -void SurfaceFlinger::performSetActiveMode() { +void SurfaceFlinger::setActiveModeInHwcIfNeeded() { ATRACE_CALL(); - ALOGV("%s", __FUNCTION__); + + std::optional<PhysicalDisplayId> displayToUpdateImmediately; for (const auto& iter : mDisplays) { const auto& display = iter.second; @@ -1254,8 +1228,7 @@ void SurfaceFlinger::performSetActiveMode() { to_string(display->getId()).c_str()); if (display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) { - // display is not valid or we are already in the requested mode - // on both cases there is nothing left to do + // we are already in the requested mode, there is nothing left to do desiredActiveModeChangeDone(display); continue; } @@ -1266,7 +1239,7 @@ void SurfaceFlinger::performSetActiveMode() { const auto displayModeAllowed = display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId()); if (!displayModeAllowed) { - desiredActiveModeChangeDone(display); + clearDesiredActiveModeState(display); continue; } @@ -1276,8 +1249,10 @@ void SurfaceFlinger::performSetActiveMode() { constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline outTimeline; - const auto status = MAIN_THREAD_GUARD( - display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline)); + const auto status = FTL_FAKE_GUARD(kMainThreadContext, + display->initiateModeChange(*desiredActiveMode, + constraints, &outTimeline)); + if (status != NO_ERROR) { // initiateModeChange may fail if a hotplug event is just about // to be sent. We just log the error in this case. @@ -1286,33 +1261,53 @@ void SurfaceFlinger::performSetActiveMode() { } mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline); - // Scheduler will submit an empty frame to HWC if needed. - mSetActiveModePending = true; + if (outTimeline.refreshRequired) { + scheduleComposite(FrameHint::kNone); + mSetActiveModePending = true; + } else { + // Updating the internal state should be done outside the loop, + // because it can recreate a DisplayDevice and modify mDisplays + // which will invalidate the iterator. + displayToUpdateImmediately = display->getPhysicalId(); + } + } + + if (displayToUpdateImmediately) { + updateInternalStateWithChangedMode(); + + const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately); + const auto desiredActiveMode = display->getDesiredActiveMode(); + if (desiredActiveMode && + display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) { + desiredActiveModeChangeDone(display); + } } } void SurfaceFlinger::disableExpensiveRendering() { - schedule([=]() MAIN_THREAD { - ATRACE_CALL(); - if (mPowerAdvisor.isUsingExpensiveRendering()) { - const auto& displays = ON_MAIN_THREAD(mDisplays); - for (const auto& [_, display] : displays) { - const static constexpr auto kDisable = false; - mPowerAdvisor.setExpensiveRenderingExpected(display->getId(), kDisable); + const char* const whence = __func__; + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { + ATRACE_NAME(whence); + if (mPowerAdvisor->isUsingExpensiveRendering()) { + for (const auto& [_, display] : mDisplays) { + constexpr bool kDisable = false; + mPowerAdvisor->setExpensiveRenderingExpected(display->getId(), kDisable); } } - }).wait(); + }); + + future.wait(); } -std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) { - auto modes = getHwComposer().getColorModes(displayId); - bool isInternalDisplay = displayId == getInternalDisplayIdLocked(); +std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(const DisplayDevice& display) { + auto modes = getHwComposer().getColorModes(display.getPhysicalId()); - // If it's built-in display and the configuration claims it's not wide color capable, + // If the display is internal and the configuration claims it's not wide color capable, // filter out all wide color modes. The typical reason why this happens is that the // hardware is not good enough to support GPU composition of wide color, and thus the // OEMs choose to disable this capability. - if (isInternalDisplay && !hasWideColorDisplay) { + if (display.getConnectionType() == ui::DisplayConnectionType::Internal && + !hasWideColorDisplay) { const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode); modes.erase(newEnd, modes.end()); } @@ -1321,69 +1316,135 @@ std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId di } status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken, - ui::DisplayPrimaries &primaries) { + ui::DisplayPrimaries& primaries) { if (!displayToken) { return BAD_VALUE; } - // Currently we only support this API for a single internal display. - if (getInternalDisplayToken() != displayToken) { + Mutex::Autolock lock(mStateLock); + + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { return NAME_NOT_FOUND; } - memcpy(&primaries, &mInternalDisplayPrimaries, sizeof(ui::DisplayPrimaries)); + const auto connectionType = display->getConnectionType(); + if (connectionType != ui::DisplayConnectionType::Internal) { + return INVALID_OPERATION; + } + + // TODO(b/229846990): For now, assume that all internal displays have the same primaries. + primaries = mInternalDisplayPrimaries; return NO_ERROR; } status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) { - schedule([=]() MAIN_THREAD { - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - ALOGE("Invalid display token %p", displayToken.get()); - return; - } - const auto modes = getDisplayColorModes(*displayId); - bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes); - if (mode < ColorMode::NATIVE || !exists) { - ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p", - decodeColorMode(mode).c_str(), mode, displayToken.get()); - return; - } + if (!displayToken) { + return BAD_VALUE; + } + + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p", decodeColorMode(mode).c_str(), mode, displayToken.get()); - } else if (display->isVirtual()) { + return NAME_NOT_FOUND; + } + + if (display->isVirtual()) { ALOGW("Attempt to set active color mode %s (%d) for virtual display", decodeColorMode(mode).c_str(), mode); - } else { - display->getCompositionDisplay()->setColorProfile( - compositionengine::Output::ColorProfile{mode, Dataspace::UNKNOWN, - RenderIntent::COLORIMETRIC, - Dataspace::UNKNOWN}); + return INVALID_OPERATION; + } + + const auto modes = getDisplayColorModes(*display); + const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end(); + + if (mode < ColorMode::NATIVE || !exists) { + ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p", + decodeColorMode(mode).c_str(), mode, displayToken.get()); + return BAD_VALUE; } - }).wait(); + display->getCompositionDisplay()->setColorProfile( + {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); + + return NO_ERROR; + }); + + // TODO(b/195698395): Propagate error. + future.wait(); return NO_ERROR; } +status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const { + auto future = mScheduler->schedule( + [this] { return getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG); }); + + *outSupport = future.get(); + return NO_ERROR; +} + +status_t SurfaceFlinger::setBootDisplayMode(const sp<IBinder>& displayToken, + ui::DisplayModeId modeId) { + const char* const whence = __func__; + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t { + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); + return NAME_NOT_FOUND; + } + + if (display->isVirtual()) { + ALOGE("%s: Invalid operation on virtual display", whence); + return INVALID_OPERATION; + } + + const auto displayId = display->getPhysicalId(); + const auto mode = display->getMode(DisplayModeId{modeId}); + if (!mode) { + ALOGE("%s: Invalid mode %d for display %s", whence, modeId, + to_string(displayId).c_str()); + return BAD_VALUE; + } + + return getHwComposer().setBootDisplayMode(displayId, mode->getHwcId()); + }); + return future.get(); +} + +status_t SurfaceFlinger::clearBootDisplayMode(const sp<IBinder>& displayToken) { + const char* const whence = __func__; + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t { + if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { + return getHwComposer().clearBootDisplayMode(*displayId); + } else { + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); + return BAD_VALUE; + } + }); + return future.get(); +} + void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) { - static_cast<void>(schedule([=]() MAIN_THREAD { + const char* const whence = __func__; + static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { getHwComposer().setAutoLowLatencyMode(*displayId, on); } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); } })); } void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) { - static_cast<void>(schedule([=]() MAIN_THREAD { + const char* const whence = __func__; + static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { const auto type = on ? hal::ContentType::GAME : hal::ContentType::NONE; getHwComposer().setContentType(*displayId, type); } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); } })); } @@ -1406,7 +1467,7 @@ status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken, auto display = getDisplayDeviceLocked(displayToken); if (!display) { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", __func__, displayToken.get()); return NAME_NOT_FOUND; } @@ -1442,17 +1503,18 @@ status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder> status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken, bool enable, uint8_t componentMask, uint64_t maxFrames) { - return schedule([=]() MAIN_THREAD -> status_t { - if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { - return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable, - componentMask, - maxFrames); - } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); - return NAME_NOT_FOUND; - } - }) - .get(); + const char* const whence = __func__; + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t { + if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { + return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable, + componentMask, maxFrames); + } else { + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); + return NAME_NOT_FOUND; + } + }); + + return future.get(); } status_t SurfaceFlinger::getDisplayedContentSample(const sp<IBinder>& displayToken, @@ -1494,14 +1556,15 @@ status_t SurfaceFlinger::isWideColorDisplay(const sp<IBinder>& displayToken, } status_t SurfaceFlinger::enableVSyncInjections(bool enable) { - schedule([=] { + auto future = mScheduler->schedule([=] { Mutex::Autolock lock(mStateLock); if (const auto handle = mScheduler->enableVSyncInjection(enable)) { - mEventQueue->setInjector(enable ? mScheduler->getEventConnection(handle) : nullptr); + mScheduler->setInjector(enable ? mScheduler->getEventConnection(handle) : nullptr); } - }).wait(); + }); + future.wait(); return NO_ERROR; } @@ -1517,12 +1580,14 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) { outLayers->clear(); - schedule([=] { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + auto future = mScheduler->schedule([=] { + const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); mDrawingState.traverseInZOrder([&](Layer* layer) { outLayers->push_back(layer->getLayerDebugInfo(display.get())); }); - }).wait(); + }); + + future.wait(); return NO_ERROR; } @@ -1540,7 +1605,7 @@ status_t SurfaceFlinger::getCompositionPreference( status_t SurfaceFlinger::addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle, const sp<IRegionSamplingListener>& listener) { - if (!listener || samplingArea == Rect::INVALID_RECT) { + if (!listener || samplingArea == Rect::INVALID_RECT || samplingArea.isEmpty()) { return BAD_VALUE; } @@ -1606,32 +1671,67 @@ status_t SurfaceFlinger::getDisplayBrightnessSupport(const sp<IBinder>& displayT if (!displayId) { return NAME_NOT_FOUND; } - *outSupport = - getHwComposer().hasDisplayCapability(*displayId, hal::DisplayCapability::BRIGHTNESS); + *outSupport = getHwComposer().hasDisplayCapability(*displayId, DisplayCapability::BRIGHTNESS); return NO_ERROR; } +bool SurfaceFlinger::hasVisibleHdrLayer(const sp<DisplayDevice>& display) { + bool hasHdrLayers = false; + mDrawingState.traverse([&, + compositionDisplay = display->getCompositionDisplay()](Layer* layer) { + hasHdrLayers |= (layer->isVisible() && + compositionDisplay->includesLayer(layer->getCompositionEngineLayerFE()) && + isHdrDataspace(layer->getDataSpace())); + }); + return hasHdrLayers; +} + status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, const gui::DisplayBrightness& brightness) { if (!displayToken) { return BAD_VALUE; } - return ftl::chain(schedule([=]() MAIN_THREAD { + const char* const whence = __func__; + return ftl::Future(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { if (const auto display = getDisplayDeviceLocked(displayToken)) { - if (enableSdrDimming) { - display->getCompositionDisplay() - ->setDisplayBrightness(brightness.sdrWhitePointNits, - brightness.displayBrightnessNits); + const bool supportsDisplayBrightnessCommand = + getHwComposer().getComposer()->isSupported( + Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand); + // If we support applying display brightness as a command, then we also support + // dimming SDR layers. + if (supportsDisplayBrightnessCommand) { + auto compositionDisplay = display->getCompositionDisplay(); + float currentDimmingRatio = + compositionDisplay->editState().sdrWhitePointNits / + compositionDisplay->editState().displayBrightnessNits; + compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits, + brightness.displayBrightnessNits); + FTL_FAKE_GUARD(kMainThreadContext, + display->stageBrightness(brightness.displayBrightness)); + + if (brightness.sdrWhitePointNits / brightness.displayBrightnessNits != + currentDimmingRatio) { + scheduleComposite(FrameHint::kNone); + } else { + scheduleCommit(FrameHint::kNone); + } + return ftl::yield<status_t>(OK); + } else { + return getHwComposer() + .setDisplayBrightness(display->getPhysicalId(), + brightness.displayBrightness, + brightness.displayBrightnessNits, + Hwc2::Composer::DisplayBrightnessOptions{ + .applyImmediately = true}); } - return getHwComposer().setDisplayBrightness(display->getPhysicalId(), - brightness.displayBrightness); + } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); return ftl::yield<status_t>(NAME_NOT_FOUND); } })) - .then([](std::future<status_t> task) { return task; }) + .then([](ftl::Future<status_t> task) { return task; }) .get(); } @@ -1680,15 +1780,33 @@ status_t SurfaceFlinger::removeHdrLayerInfoListener( } status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) { + using hardware::power::Boost; Boost powerBoost = static_cast<Boost>(boostId); if (powerBoost == Boost::INTERACTION) { - mScheduler->notifyTouchEvent(); + mScheduler->onTouchHint(); } return NO_ERROR; } +status_t SurfaceFlinger::getDisplayDecorationSupport( + const sp<IBinder>& displayToken, + std::optional<DisplayDecorationSupport>* outSupport) const { + if (!displayToken || !outSupport) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mStateLock); + + const auto displayId = getPhysicalDisplayIdLocked(displayToken); + if (!displayId) { + return NAME_NOT_FOUND; + } + getHwComposer().getDisplayDecorationSupport(*displayId, outSupport); + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( @@ -1700,21 +1818,26 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( return mScheduler->createDisplayEventConnection(handle, eventRegistration); } -void SurfaceFlinger::signalTransaction() { - mScheduler->resetIdleTimer(); - mPowerAdvisor.notifyDisplayUpdateImminent(); - mEventQueue->invalidate(); +void SurfaceFlinger::scheduleCommit(FrameHint hint) { + if (hint == FrameHint::kActive) { + mScheduler->resetIdleTimer(); + } + mPowerAdvisor->notifyDisplayUpdateImminent(); + mScheduler->scheduleFrame(); +} + +void SurfaceFlinger::scheduleComposite(FrameHint hint) { + mMustComposite = true; + scheduleCommit(hint); } -void SurfaceFlinger::signalLayerUpdate() { - mScheduler->resetIdleTimer(); - mPowerAdvisor.notifyDisplayUpdateImminent(); - mEventQueue->invalidate(); +void SurfaceFlinger::scheduleRepaint() { + mGeometryDirty = true; + scheduleComposite(FrameHint::kActive); } -void SurfaceFlinger::signalRefresh() { - mRefreshPending = true; - mEventQueue->refresh(); +void SurfaceFlinger::scheduleSample() { + static_cast<void>(mScheduler->schedule([this] { sample(); })); } nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { @@ -1727,7 +1850,15 @@ nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp, std::optional<hal::VsyncPeriodNanos> vsyncPeriod) { - ATRACE_CALL(); + const std::string tracePeriod = [vsyncPeriod]() { + if (ATRACE_ENABLED() && vsyncPeriod) { + std::stringstream ss; + ss << "(" << *vsyncPeriod << ")"; + return ss.str(); + } + return std::string(); + }(); + ATRACE_FORMAT("onComposerHalVsync%s", tracePeriod.c_str()); Mutex::Autolock lock(mStateLock); const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId); @@ -1760,28 +1891,10 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, - Scheduler::ModeEvent event) { - const auto display = getDefaultDisplayDeviceLocked(); - if (!display || mBootStage != BootStage::FINISHED) { - return; - } - ATRACE_CALL(); - - // Don't do any updating if the current fps is the same as the new one. - if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) { - ALOGV("Skipping mode %d as it is not part of allowed modes", - refreshRate.getModeId().value()); - return; - } - - setDesiredActiveMode({refreshRate.getMode(), event}); -} - void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { - ALOGI("%s(%" PRIu64 ", %s)", __func__, hwcDisplayId, - connection == hal::Connection::CONNECTED ? "connected" : "disconnected"); + const bool connected = connection == hal::Connection::CONNECTED; + ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId); // Only lock if we're not on the main thread. This function is normally // called on a hwbinder thread, but for the primary display it's called on @@ -1803,6 +1916,10 @@ void SurfaceFlinger::onComposerHalVsyncPeriodTimingChanged( hal::HWDisplayId, const hal::VsyncPeriodChangeTimeline& timeline) { Mutex::Autolock lock(mStateLock); mScheduler->onNewVsyncPeriodChangeTimeline(timeline); + + if (timeline.refreshRequired) { + scheduleComposite(FrameHint::kNone); + } } void SurfaceFlinger::onComposerHalSeamlessPossible(hal::HWDisplayId) { @@ -1812,14 +1929,19 @@ void SurfaceFlinger::onComposerHalSeamlessPossible(hal::HWDisplayId) { void SurfaceFlinger::onComposerHalRefresh(hal::HWDisplayId) { Mutex::Autolock lock(mStateLock); - repaintEverythingForHWC(); + scheduleComposite(FrameHint::kNone); +} + +void SurfaceFlinger::onComposerHalVsyncIdle(hal::HWDisplayId) { + ATRACE_CALL(); + mScheduler->forceNextResync(); } void SurfaceFlinger::setVsyncEnabled(bool enabled) { ATRACE_CALL(); // On main thread to avoid race conditions with display power state. - static_cast<void>(schedule([=]() MAIN_THREAD { + static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE; if (const auto display = getDefaultDisplayDeviceLocked(); @@ -1833,8 +1955,16 @@ SurfaceFlinger::FenceWithFenceTime SurfaceFlinger::previousFrameFence() { const auto now = systemTime(); const auto vsyncPeriod = mScheduler->getDisplayStatInfo(now).vsyncPeriod; const bool expectedPresentTimeIsTheNextVsync = mExpectedPresentTime - now <= vsyncPeriod; - return expectedPresentTimeIsTheNextVsync ? mPreviousPresentFences[0] - : mPreviousPresentFences[1]; + + size_t shift = 0; + if (!expectedPresentTimeIsTheNextVsync) { + shift = static_cast<size_t>((mExpectedPresentTime - now) / vsyncPeriod); + if (shift >= mPreviousPresentFences.size()) { + shift = mPreviousPresentFences.size() - 1; + } + } + ATRACE_FORMAT("previousFrameFence shift=%zu", shift); + return mPreviousPresentFences[shift]; } bool SurfaceFlinger::previousFramePending(int graceTimeMs) { @@ -1867,40 +1997,37 @@ nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) cons : stats.vsyncTime + stats.vsyncPeriod; } -void SurfaceFlinger::onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime) { - switch (what) { - case MessageQueue::INVALIDATE: { - onMessageInvalidate(vsyncId, expectedVSyncTime); - break; - } - case MessageQueue::REFRESH: { - onMessageRefresh(); - break; - } +bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) + FTL_FAKE_GUARD(kMainThreadContext) { + // we set this once at the beginning of commit to ensure consistency throughout the whole frame + mPowerHintSessionData.sessionEnabled = mPowerAdvisor->usePowerHintSession(); + if (mPowerHintSessionData.sessionEnabled) { + mPowerHintSessionData.commitStart = systemTime(); } -} -void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime) { - const nsecs_t frameStart = systemTime(); // calculate the expected present time once and use the cached // value throughout this frame to make sure all layers are // seeing this same value. - if (expectedVSyncTime >= frameStart) { - mExpectedPresentTime = expectedVSyncTime; + if (expectedVsyncTime >= frameTime) { + mExpectedPresentTime = expectedVsyncTime; } else { - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameStart); + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameTime); mExpectedPresentTime = calculateExpectedPresentTime(stats); } const nsecs_t lastScheduledPresentTime = mScheduledPresentTime; - mScheduledPresentTime = expectedVSyncTime; + mScheduledPresentTime = expectedVsyncTime; + if (mPowerHintSessionData.sessionEnabled) { + mPowerAdvisor->setTargetWorkDuration(mExpectedPresentTime - + mPowerHintSessionData.commitStart); + } const auto vsyncIn = [&] { if (!ATRACE_ENABLED()) return 0.f; return (mExpectedPresentTime - systemTime()) / 1e6f; }(); - ATRACE_FORMAT("onMessageInvalidate %" PRId64 " vsyncIn %.2fms%s", vsyncId, vsyncIn, - mExpectedPresentTime == expectedVSyncTime ? "" : " (adjusted)"); + ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId, vsyncIn, + mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)"); // When Backpressure propagation is enabled we want to give a small grace period // for the present fence to fire instead of just giving up on this frame to handle cases @@ -1947,11 +2074,11 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT } // If we are in the middle of a mode change and the fence hasn't - // fired yet just wait for the next invalidate + // fired yet just wait for the next commit. if (mSetActiveModePending) { if (framePending) { - mEventQueue->invalidate(); - return; + mScheduler->scheduleFrame(); + return false; } // We received the present fence from the HWC, so we assume it successfully updated @@ -1959,50 +2086,64 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT mSetActiveModePending = false; { Mutex::Autolock lock(mStateLock); - setActiveModeInternal(); + updateInternalStateWithChangedMode(); } } if (framePending) { if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) { - signalLayerUpdate(); - return; + scheduleCommit(FrameHint::kNone); + return false; } } if (mTracingEnabledChanged) { - mTracingEnabled = mTracing.isEnabled(); + mLayerTracingEnabled = mLayerTracing.isEnabled(); mTracingEnabledChanged = false; } if (mRefreshRateOverlaySpinner) { - if (Mutex::Autolock lock(mStateLock); - const auto display = getDefaultDisplayDeviceLocked()) { - if (display) { - display->onInvalidate(); - } else { - ALOGW("%s: default display is null", __func__); - } + Mutex::Autolock lock(mStateLock); + if (const auto display = getDefaultDisplayDeviceLocked()) { + display->animateRefreshRateOverlay(); } } - bool refreshNeeded; + // Composite if transactions were committed, or if requested by HWC. + bool mustComposite = mMustComposite.exchange(false); { - mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) || - mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) || - mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS); - const bool tracePreComposition = mTracingEnabled && !mTracePostComposition; - ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition); - - mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod)); - - refreshNeeded = handleMessageTransaction(); - refreshNeeded |= handleMessageInvalidate(); - if (tracePreComposition) { - if (mVisibleRegionsDirty) { - mTracing.notifyLocked("visibleRegionsDirty"); - } + mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod)); + + bool needsTraversal = false; + if (clearTransactionFlags(eTransactionFlushNeeded)) { + needsTraversal |= commitCreatedLayers(); + needsTraversal |= flushTransactionQueues(vsyncId); + } + + const bool shouldCommit = + (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal; + if (shouldCommit) { + commitTransactions(); } + + if (transactionFlushNeeded()) { + setTransactionFlags(eTransactionFlushNeeded); + } + + mustComposite |= shouldCommit; + mustComposite |= latchBuffers(); + + // This has to be called after latchBuffers because we want to include the layers that have + // been latched in the commit callback + if (!needsTraversal) { + // Invoke empty transaction callbacks early. + mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); + } else { + // Invoke OnCommit callbacks. + mTransactionCallbackInvoker.sendCallbacks(true /* onCommitOnly */); + } + + updateLayerGeometry(); } // Layers need to get updated (in the previous line) before we can use them for @@ -2012,63 +2153,32 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT { Mutex::Autolock _l(mStateLock); mScheduler->chooseRefreshRateForContent(); + setActiveModeInHwcIfNeeded(); } - ON_MAIN_THREAD(performSetActiveMode()); - updateCursorAsync(); updateInputFlinger(); - refreshNeeded |= mRepaintEverything; - if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) { - // Signal a refresh if a transaction modified the window state, - // a new buffer was latched, or if HWC has requested a full - // repaint - if (mFrameStartTime <= 0) { - // We should only use the time of the first invalidate - // message that signals a refresh as the beginning of the - // frame. Otherwise the real frame time will be - // underestimated. - mFrameStartTime = frameStart; - } - - // Run the refresh immediately after invalidate as there is no point going thru the message - // queue again, and to ensure that we actually refresh the screen instead of handling - // other messages that were queued us already in the MessageQueue. - mRefreshPending = true; - onMessageRefresh(); - } - notifyRegionSamplingThread(); -} - -bool SurfaceFlinger::handleMessageTransaction() { - ATRACE_CALL(); - - if (getTransactionFlags(eTransactionFlushNeeded)) { - flushTransactionQueues(); + if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { + // This will block and tracing should only be enabled for debugging. + mLayerTracing.notify(mVisibleRegionsDirty, frameTime); } - uint32_t transactionFlags = peekTransactionFlags(); - bool runHandleTransaction = - ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal; - if (runHandleTransaction) { - handleTransaction(eTransactionMask); - } - - if (transactionFlushNeeded()) { - setTransactionFlags(eTransactionFlushNeeded); - } + persistDisplayBrightness(mustComposite); - return runHandleTransaction; + return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER); } -void SurfaceFlinger::onMessageRefresh() { - ATRACE_CALL(); +void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) + FTL_FAKE_GUARD(kMainThreadContext) { + ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId); - mRefreshPending = false; + if (mPowerHintSessionData.sessionEnabled) { + mPowerHintSessionData.compositeStart = systemTime(); + } compositionengine::CompositionRefreshArgs refreshArgs; - const auto& displays = ON_MAIN_THREAD(mDisplays); + const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays); refreshArgs.outputs.reserve(displays.size()); for (const auto& [_, display] : displays) { refreshArgs.outputs.push_back(display->getCompositionDisplay()); @@ -2083,7 +2193,6 @@ void SurfaceFlinger::onMessageRefresh() { refreshArgs.layersWithQueuedFrames.push_back(layerFE); } - refreshArgs.repaintEverything = mRepaintEverything.exchange(false); refreshArgs.outputColorSetting = useColorManagement ? mDisplayColorSetting : compositionengine::OutputColorSetting::kUnmanaged; @@ -2091,7 +2200,7 @@ void SurfaceFlinger::onMessageRefresh() { refreshArgs.forceOutputColorMode = mForceColorMode; refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty; - refreshArgs.updatingGeometryThisFrame = mGeometryInvalid || mVisibleRegionsDirty; + refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty; refreshArgs.blursAreExpensive = mBlursAreExpensive; refreshArgs.internalDisplayRotationFlags = DisplayDevice::getPrimaryDisplayRotationFlags(); @@ -2100,83 +2209,87 @@ void SurfaceFlinger::onMessageRefresh() { mDrawingState.colorMatrixChanged = false; } - refreshArgs.devOptForceClientComposition = mDebugDisableHWC || mDebugRegion; + refreshArgs.devOptForceClientComposition = mDebugDisableHWC; - if (mDebugRegion != 0) { - refreshArgs.devOptFlashDirtyRegionsDelay = - std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0); + if (mDebugFlashDelay != 0) { + refreshArgs.devOptForceClientComposition = true; + refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay); } - const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(mExpectedPresentTime); + const auto expectedPresentTime = mExpectedPresentTime.load(); + const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(expectedPresentTime); const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration; refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration; refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime; - refreshArgs.nextInvalidateTime = mEventQueue->nextExpectedInvalidate(); - - mGeometryInvalid = false; + refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime(); + refreshArgs.expectedPresentTime = expectedPresentTime; // 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); + if (mPowerHintSessionData.sessionEnabled) { + mPowerHintSessionData.presentEnd = systemTime(); + } + + mTimeStats->recordFrameDuration(frameTime, systemTime()); + + if (mScheduler->onPostComposition(presentTime)) { + scheduleComposite(FrameHint::kNone); + } 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(); + mHadClientComposition = mHadDeviceComposition = mReusedClientComposition = false; + TimeStats::ClientCompositionRecord clientCompositionRecord; + for (const auto& [_, display] : displays) { + const auto& state = display->getCompositionDisplay()->getState(); + mHadClientComposition |= state.usesClientComposition && !state.reusedClientComposition; + mHadDeviceComposition |= state.usesDeviceComposition; + mReusedClientComposition |= state.reusedClientComposition; + clientCompositionRecord.predicted |= + (state.strategyPrediction != CompositionStrategyPredictionState::DISABLED); + clientCompositionRecord.predictionSucceeded |= + (state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS); } + clientCompositionRecord.hadClientComposition = mHadClientComposition; + clientCompositionRecord.reused = mReusedClientComposition; + clientCompositionRecord.changed = prevFrameHadClientComposition != mHadClientComposition; + mTimeStats->pushCompositionStrategyState(clientCompositionRecord); + // 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"); - } + if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { + // This will block and should only be used for debugging. + mLayerTracing.notify(mVisibleRegionsDirty, frameTime); } mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp mVisibleRegionsDirty = false; if (mCompositionEngine->needsAnotherUpdate()) { - signalLayerUpdate(); + scheduleCommit(FrameHint::kNone); + } + + // calculate total render time for performance hinting if adpf cpu hint is enabled, + if (mPowerHintSessionData.sessionEnabled) { + const nsecs_t flingerDuration = + (mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart); + mPowerAdvisor->sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd); } } -bool SurfaceFlinger::handleMessageInvalidate() { +void SurfaceFlinger::updateLayerGeometry() { ATRACE_CALL(); - bool refreshNeeded = handlePageFlip(); - - // Send on commit callbacks - mTransactionCallbackInvoker.sendCallbacks(); if (mVisibleRegionsDirty) { computeLayerBounds(); @@ -2188,7 +2301,6 @@ bool SurfaceFlinger::handleMessageInvalidate() { invalidateLayerStack(layer, visibleReg); } mLayersPendingRefresh.clear(); - return refreshNeeded; } void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, @@ -2219,16 +2331,19 @@ void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_ void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats, nsecs_t compositeToPresentLatency) { + // Avoid division by 0 by defaulting to 60Hz + const auto vsyncPeriod = stats.vsyncPeriod ?: (60_Hz).getPeriodNsecs(); + // Integer division and modulo round toward 0 not -inf, so we need to // treat negative and positive offsets differently. nsecs_t idealLatency = (mVsyncConfiguration->getCurrentConfigs().late.sfOffset > 0) - ? (stats.vsyncPeriod - - (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % stats.vsyncPeriod)) - : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % stats.vsyncPeriod); + ? (vsyncPeriod - + (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % vsyncPeriod)) + : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % vsyncPeriod); // Just in case mVsyncConfiguration->getCurrentConfigs().late.sf == -vsyncInterval. if (idealLatency <= 0) { - idealLatency = stats.vsyncPeriod; + idealLatency = vsyncPeriod; } // Snap the latency to a value that removes scheduling jitter from the @@ -2237,44 +2352,96 @@ void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats, // something (such as user input) to an accurate diasplay time. // Snapping also allows an app to precisely calculate // mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval). - nsecs_t bias = stats.vsyncPeriod / 2; - int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod; - nsecs_t snappedCompositeToPresentLatency = - (extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency; + const nsecs_t bias = vsyncPeriod / 2; + const int64_t extraVsyncs = ((compositeToPresentLatency - idealLatency + bias) / vsyncPeriod); + const nsecs_t snappedCompositeToPresentLatency = + (extraVsyncs > 0) ? idealLatency + (extraVsyncs * vsyncPeriod) : idealLatency; std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency; - getBE().mCompositorTiming.interval = stats.vsyncPeriod; + getBE().mCompositorTiming.interval = vsyncPeriod; getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency; } +bool SurfaceFlinger::isHdrLayer(Layer* layer) const { + // Treat all layers as non-HDR if: + // 1. They do not have a valid HDR dataspace. Currently we treat those as PQ or HLG. and + // 2. The layer is allowed to be dimmed. WindowManager may disable dimming in order to + // keep animations invoking SDR screenshots of HDR layers seamless. Treat such tagged + // layers as HDR so that DisplayManagerService does not try to change the screen brightness + if (!isHdrDataspace(layer->getDataSpace()) && layer->isDimmingEnabled()) { + return false; + } + if (mIgnoreHdrCameraLayers) { + auto buffer = layer->getBuffer(); + if (buffer && (buffer->getUsage() & GRALLOC_USAGE_HW_CAMERA_WRITE) != 0) { + return false; + } + } + return true; +} + +ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId, + bool isPrimary) const { + const auto id = PhysicalDisplayId::tryCast(displayId); + if (!id) { + return ui::ROTATION_0; + } + if (getHwComposer().getComposer()->isSupported( + Hwc2::Composer::OptionalFeature::PhysicalDisplayOrientation)) { + switch (getHwComposer().getPhysicalDisplayOrientation(*id)) { + case Hwc2::AidlTransform::ROT_90: + return ui::ROTATION_90; + case Hwc2::AidlTransform::ROT_180: + return ui::ROTATION_180; + case Hwc2::AidlTransform::ROT_270: + return ui::ROTATION_270; + default: + return ui::ROTATION_0; + } + } + + if (isPrimary) { + using Values = SurfaceFlingerProperties::primary_display_orientation_values; + switch (primary_display_orientation(Values::ORIENTATION_0)) { + case Values::ORIENTATION_90: + return ui::ROTATION_90; + case Values::ORIENTATION_180: + return ui::ROTATION_180; + case Values::ORIENTATION_270: + return ui::ROTATION_270; + default: + break; + } + } + return ui::ROTATION_0; +} + void SurfaceFlinger::postComposition() { ATRACE_CALL(); ALOGV("postComposition"); - const auto* display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()).get(); + const auto* display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get(); - getBE().mGlCompositionDoneTimeline.updateSignalTimes(); std::shared_ptr<FenceTime> glCompositionDoneFenceTime; if (display && display->getCompositionDisplay()->getState().usesClientComposition) { glCompositionDoneFenceTime = std::make_shared<FenceTime>(display->getCompositionDisplay() ->getRenderSurface() ->getClientTargetAcquireFence()); - getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime); } else { glCompositionDoneFenceTime = FenceTime::NO_FENCE; } - getBE().mDisplayTimeline.updateSignalTimes(); - mPreviousPresentFences[1] = mPreviousPresentFences[0]; + for (size_t i = mPreviousPresentFences.size()-1; i >= 1; i--) { + mPreviousPresentFences[i] = mPreviousPresentFences[i-1]; + } + mPreviousPresentFences[0].fence = display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE; mPreviousPresentFences[0].fenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0].fence); - getBE().mDisplayTimeline.push(mPreviousPresentFences[0].fenceTime); - nsecs_t now = systemTime(); // Set presentation information before calling Layer::releasePendingBuffer, such that jank @@ -2297,13 +2464,9 @@ void SurfaceFlinger::postComposition() { } for (const auto& layer: mLayersWithQueuedFrames) { - const bool frameLatched = - layer->onPostComposition(display, glCompositionDoneFenceTime, - mPreviousPresentFences[0].fenceTime, compositorTiming); + layer->onPostComposition(display, glCompositionDoneFenceTime, + mPreviousPresentFences[0].fenceTime, compositorTiming); layer->releasePendingBuffer(/*dequeueReadyTime*/ now); - if (frameLatched) { - recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false)); - } } std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>> @@ -2336,13 +2499,8 @@ void SurfaceFlinger::postComposition() { int32_t maxArea = 0; mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) { const auto layerFe = layer->getCompositionEngineLayerFE(); - if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) { - const Dataspace transfer = - static_cast<Dataspace>(layer->getDataSpace() & Dataspace::TRANSFER_MASK); - const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 || - transfer == Dataspace::TRANSFER_HLG); - - if (isHdr) { + if (layer->isVisible() && compositionDisplay->includesLayer(layerFe)) { + if (isHdrLayer(layer)) { const auto* outputLayer = compositionDisplay->getOutputLayerForLayer(layerFe); if (outputLayer) { @@ -2366,7 +2524,8 @@ void SurfaceFlinger::postComposition() { mVisibleRegionsWereDirtyThisFrame = false; mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence); - mTransactionCallbackInvoker.sendCallbacks(); + mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); + mTransactionCallbackInvoker.clearCompletedTransactions(); if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON && mPreviousPresentFences[0].fenceTime->isValid()) { @@ -2397,13 +2556,6 @@ void SurfaceFlinger::postComposition() { } mTimeStats->incrementTotalFrames(); - if (mHadClientComposition) { - mTimeStats->incrementClientCompositionFrames(); - } - - if (mReusedClientComposition) { - mTimeStats->incrementClientCompositionReusedFrames(); - } mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime); @@ -2460,37 +2612,37 @@ void SurfaceFlinger::postComposition() { } FloatRect SurfaceFlinger::getMaxDisplayBounds() { - // Find the largest width and height among all the displays. - int32_t maxDisplayWidth = 0; - int32_t maxDisplayHeight = 0; - for (const auto& pair : ON_MAIN_THREAD(mDisplays)) { - const auto& displayDevice = pair.second; - int32_t width = displayDevice->getWidth(); - int32_t height = displayDevice->getHeight(); - if (width > maxDisplayWidth) { - maxDisplayWidth = width; - } - if (height > maxDisplayHeight) { - maxDisplayHeight = height; - } - } + const ui::Size maxSize = [this] { + ftl::FakeGuard guard(mStateLock); + + // The LayerTraceGenerator tool runs without displays. + if (mDisplays.empty()) return ui::Size{5000, 5000}; + + return std::accumulate(mDisplays.begin(), mDisplays.end(), ui::kEmptySize, + [](ui::Size size, const auto& pair) -> ui::Size { + const auto& display = pair.second; + return {std::max(size.getWidth(), display->getWidth()), + std::max(size.getHeight(), display->getHeight())}; + }); + }(); // Ignore display bounds for now since they will be computed later. Use a large Rect bound // to ensure it's bigger than an actual display will be. - FloatRect maxBounds = FloatRect(-maxDisplayWidth * 10, -maxDisplayHeight * 10, - maxDisplayWidth * 10, maxDisplayHeight * 10); - return maxBounds; + const float xMax = maxSize.getWidth() * 10.f; + const float yMax = maxSize.getHeight() * 10.f; + + return {-xMax, -yMax, xMax, yMax}; } void SurfaceFlinger::computeLayerBounds() { - FloatRect maxBounds = getMaxDisplayBounds(); + const FloatRect maxBounds = getMaxDisplayBounds(); for (const auto& layer : mDrawingState.layersSortedByZ) { layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */); } } void SurfaceFlinger::postFrame() { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); if (display && getHwComposer().isConnected(display->getPhysicalId())) { uint32_t flipCount = display->getPageFlipCount(); if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { @@ -2499,36 +2651,33 @@ void SurfaceFlinger::postFrame() { } } -void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { +void SurfaceFlinger::commitTransactions() { ATRACE_CALL(); - // here we keep a copy of the drawing state (that is the state that's - // going to be overwritten by handleTransactionLocked()) outside of - // mStateLock so that the side-effects of the State assignment - // don't happen with mStateLock held (which can cause deadlocks). + // Keep a copy of the drawing state (that is going to be overwritten + // by commitTransactionsLocked) outside of mStateLock so that the side + // effects of the State assignment don't happen with mStateLock held, + // which can cause deadlocks. State drawingState(mDrawingState); - Mutex::Autolock _l(mStateLock); + Mutex::Autolock lock(mStateLock); mDebugInTransaction = systemTime(); // Here we're guaranteed that some transaction flags are set - // so we can call handleTransactionLocked() unconditionally. - // We call getTransactionFlags(), which will also clear the flags, - // with mStateLock held to guarantee that mCurrentState won't change - // until the transaction is committed. + // so we can call commitTransactionsLocked unconditionally. + // We clear the flags with mStateLock held to guarantee that + // mCurrentState won't change until the transaction is committed. modulateVsync(&VsyncModulator::onTransactionCommit); - transactionFlags = getTransactionFlags(eTransactionMask); - handleTransactionLocked(transactionFlags); + commitTransactionsLocked(clearTransactionFlags(eTransactionMask)); mDebugInTransaction = 0; - // here the transaction has been committed } -void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes, - DisplayModePtr& outActiveMode) const { +std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( + PhysicalDisplayId displayId) const { std::vector<HWComposer::HWCDisplayMode> hwcModes; std::optional<hal::HWDisplayId> activeModeHwcId; - bool activeModeIsSupported; + int attempt = 0; constexpr int kMaxAttempts = 3; do { @@ -2536,63 +2685,60 @@ void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& activeModeHwcId = getHwComposer().getActiveMode(displayId); LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active mode"); - activeModeIsSupported = - std::any_of(hwcModes.begin(), hwcModes.end(), - [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) { - return mode.hwcId == *activeModeHwcId; - }); - } while (!activeModeIsSupported && ++attempt < kMaxAttempts); - LOG_ALWAYS_FATAL_IF(!activeModeIsSupported, + const auto isActiveMode = [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) { + return mode.hwcId == *activeModeHwcId; + }; + + if (std::any_of(hwcModes.begin(), hwcModes.end(), isActiveMode)) { + break; + } + } while (++attempt < kMaxAttempts); + + LOG_ALWAYS_FATAL_IF(attempt == kMaxAttempts, "After %d attempts HWC still returns an active mode which is not" - " supported. Active mode ID = %" PRIu64 " . Supported modes = %s", + " supported. Active mode ID = %" PRIu64 ". Supported modes = %s", kMaxAttempts, *activeModeHwcId, base::Join(hwcModes, ", ").c_str()); DisplayModes oldModes; - if (const auto token = getPhysicalDisplayTokenLocked(displayId)) { oldModes = getDisplayDeviceLocked(token)->getSupportedModes(); } - int largestUsedModeId = -1; // Use int instead of DisplayModeId for signedness - for (const auto& mode : oldModes) { - const auto id = static_cast<int>(mode->getId().value()); - if (id > largestUsedModeId) { - largestUsedModeId = id; - } - } + ui::DisplayModeId nextModeId = 1 + + std::accumulate(oldModes.begin(), oldModes.end(), static_cast<ui::DisplayModeId>(-1), + [](ui::DisplayModeId max, const auto& pair) { + return std::max(max, pair.first.value()); + }); DisplayModes newModes; - int32_t nextModeId = largestUsedModeId + 1; for (const auto& hwcMode : hwcModes) { - newModes.push_back(DisplayMode::Builder(hwcMode.hwcId) - .setId(DisplayModeId{nextModeId++}) - .setPhysicalDisplayId(displayId) - .setWidth(hwcMode.width) - .setHeight(hwcMode.height) - .setVsyncPeriod(hwcMode.vsyncPeriod) - .setDpiX(hwcMode.dpiX) - .setDpiY(hwcMode.dpiY) - .setGroup(hwcMode.configGroup) - .build()); - } - - const bool modesAreSame = + const DisplayModeId id{nextModeId++}; + newModes.try_emplace(id, + DisplayMode::Builder(hwcMode.hwcId) + .setId(id) + .setPhysicalDisplayId(displayId) + .setResolution({hwcMode.width, hwcMode.height}) + .setVsyncPeriod(hwcMode.vsyncPeriod) + .setDpiX(hwcMode.dpiX) + .setDpiY(hwcMode.dpiY) + .setGroup(hwcMode.configGroup) + .build()); + } + + const bool sameModes = std::equal(newModes.begin(), newModes.end(), oldModes.begin(), oldModes.end(), - [](DisplayModePtr left, DisplayModePtr right) { - return left->equalsExceptDisplayModeId(right); + [](const auto& lhs, const auto& rhs) { + return equalsExceptDisplayModeId(*lhs.second, *rhs.second); }); - if (modesAreSame) { - // The supported modes have not changed, keep the old IDs. - outModes = oldModes; - } else { - outModes = newModes; - } + // Keep IDs if modes have not changed. + const auto& modes = sameModes ? oldModes : newModes; + const DisplayModePtr activeMode = + std::find_if(modes.begin(), modes.end(), [activeModeHwcId](const auto& pair) { + return pair.second->getHwcId() == activeModeHwcId; + })->second; - outActiveMode = *std::find_if(outModes.begin(), outModes.end(), - [activeModeHwcId](const DisplayModePtr& mode) { - return mode->getHwcId() == *activeModeHwcId; - }); + return {modes, activeMode}; } void SurfaceFlinger::processDisplayHotplugEventsLocked() { @@ -2605,14 +2751,12 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { } const auto displayId = info->id; - const auto it = mPhysicalDisplayTokens.find(displayId); + const auto token = mPhysicalDisplayTokens.get(displayId); if (event.connection == hal::Connection::CONNECTED) { - DisplayModes supportedModes; - DisplayModePtr activeMode; - loadDisplayModes(displayId, supportedModes, activeMode); + auto [supportedModes, activeMode] = loadDisplayModes(displayId); - if (it == mPhysicalDisplayTokens.end()) { + if (!token) { ALOGV("Creating display %s", to_string(displayId).c_str()); DisplayDeviceState state; @@ -2621,22 +2765,21 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { .hwcDisplayId = event.hwcDisplayId, .deviceProductInfo = std::move(info->deviceProductInfo), .supportedModes = std::move(supportedModes), - .activeMode = activeMode}; + .activeMode = std::move(activeMode)}; state.isSecure = true; // All physical displays are currently considered secure. state.displayName = std::move(info->name); sp<IBinder> token = new BBinder(); mCurrentState.displays.add(token, state); - mPhysicalDisplayTokens.emplace(displayId, std::move(token)); + mPhysicalDisplayTokens.try_emplace(displayId, std::move(token)); mInterceptor->saveDisplayCreation(state); } else { ALOGV("Recreating display %s", to_string(displayId).c_str()); - const auto token = it->second; - auto& state = mCurrentState.displays.editValueFor(token); - state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId + auto& state = mCurrentState.displays.editValueFor(token->get()); + state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId. state.physical->supportedModes = std::move(supportedModes); - state.physical->activeMode = activeMode; + state.physical->activeMode = std::move(activeMode); if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) { state.physical->deviceProductInfo = std::move(info->deviceProductInfo); } @@ -2644,13 +2787,13 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { } else { ALOGV("Removing display %s", to_string(displayId).c_str()); - const ssize_t index = mCurrentState.displays.indexOfKey(it->second); - if (index >= 0) { + if (const ssize_t index = mCurrentState.displays.indexOfKey(token->get()); index >= 0) { const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); mInterceptor->saveDisplayDeletion(state.sequenceId); mCurrentState.displays.removeItemsAt(index); } - mPhysicalDisplayTokens.erase(it); + + mPhysicalDisplayTokens.erase(displayId); } processDisplayChangesLocked(); @@ -2683,21 +2826,22 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( creationArgs.connectionType = physical->type; creationArgs.supportedModes = physical->supportedModes; creationArgs.activeModeId = physical->activeMode->getId(); - const auto [idleTimerTimeoutMs, supportKernelIdleTimer] = - getIdleTimerConfiguration(compositionDisplay->getId()); + const auto [kernelIdleTimerController, idleTimerTimeoutMs] = + getKernelIdleTimerProperties(compositionDisplay->getId()); + scheduler::RefreshRateConfigs::Config config = {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false), .frameRateMultipleThreshold = base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0), - .idleTimerTimeoutMs = idleTimerTimeoutMs, - .supportKernelIdleTimer = supportKernelIdleTimer}; + .idleTimerTimeout = idleTimerTimeoutMs, + .kernelIdleTimerController = kernelIdleTimerController}; creationArgs.refreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(creationArgs.supportedModes, creationArgs.activeModeId, config); } if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) { - creationArgs.isPrimary = id == getInternalDisplayIdLocked(); + creationArgs.isPrimary = id == getPrimaryDisplayIdLocked(); if (useColorManagement) { std::vector<ColorMode> modes = getHwComposer().getColorModes(*id); @@ -2730,7 +2874,8 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( } creationArgs.physicalOrientation = - creationArgs.isPrimary ? internalDisplayOrientation : ui::ROTATION_0; + getPhysicalDisplayOrientation(compositionDisplay->getId(), creationArgs.isPrimary); + ALOGV("Display Orientation: %s", toCString(creationArgs.physicalOrientation)); // virtual displays are always considered enabled creationArgs.initialPowerMode = state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF; @@ -2750,7 +2895,8 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); if (!state.isVirtual()) { - MAIN_THREAD_GUARD(display->setActiveMode(state.physical->activeMode->getId())); + FTL_FAKE_GUARD(kMainThreadContext, + display->setActiveMode(state.physical->activeMode->getId())); display->setDeviceProductInfo(state.physical->deviceProductInfo); } @@ -2758,6 +2904,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( display->setProjection(state.orientation, state.layerStackSpaceRect, state.orientedDisplaySpaceRect); display->setDisplayName(state.displayName); + display->setFlags(state.flags); return display; } @@ -2767,7 +2914,7 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, ui::Size resolution(0, 0); ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN); if (state.physical) { - resolution = state.physical->activeMode->getSize(); + resolution = state.physical->activeMode->getResolution(); pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888); } else if (state.surface != nullptr) { int status = state.surface->query(NATIVE_WINDOW_WIDTH, &resolution.width); @@ -2788,15 +2935,13 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, compositionengine::DisplayCreationArgsBuilder builder; if (const auto& physical = state.physical) { builder.setId(physical->id); - builder.setConnectionType(physical->type); } else { builder.setId(acquireVirtualDisplay(resolution, pixelFormat)); } builder.setPixels(resolution); builder.setIsSecure(state.isSecure); - builder.setLayerStackId(state.layerStack); - builder.setPowerAdvisor(&mPowerAdvisor); + builder.setPowerAdvisor(mPowerAdvisor.get()); builder.setName(state.displayName); auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled); @@ -2823,21 +2968,22 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, LOG_FATAL_IF(!displayId); displaySurface = sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqConsumer, - state.physical->activeMode->getSize(), + state.physical->activeMode->getResolution(), ui::Size(maxGraphicsWidth, maxGraphicsHeight)); producer = bqProducer; } LOG_FATAL_IF(!displaySurface); - const auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay), - state, displaySurface, producer); - mDisplays.emplace(displayToken, display); + auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay), state, + displaySurface, producer); if (display->isPrimary()) { initScheduler(display); } if (!state.isVirtual()) { dispatchDisplayHotplugEvent(display->getPhysicalId(), true); } + + mDisplays.try_emplace(displayToken, std::move(display)); } void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { @@ -2855,7 +3001,7 @@ void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { mDisplays.erase(displayToken); if (display && display->isVirtual()) { - static_cast<void>(schedule([display = std::move(display)] { + static_cast<void>(mScheduler->schedule([display = std::move(display)] { // Destroy the display without holding the mStateLock. // This is a temporary solution until we can manage transaction queues without // holding the mStateLock. @@ -2901,7 +3047,7 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, setPowerModeInternal(display, hal::PowerMode::ON); // TODO(b/175678251) Call a listener instead. - if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { + if (currentState.physical->hwcDisplayId == getHwComposer().getPrimaryHwcDisplayId()) { updateInternalDisplayVsyncLocked(display); } } @@ -2936,7 +3082,7 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, } void SurfaceFlinger::updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) { mVsyncConfiguration->reset(); - const Fps refreshRate = activeDisplay->refreshRateConfigs().getCurrentRefreshRate().getFps(); + const Fps refreshRate = activeDisplay->refreshRateConfigs().getActiveMode()->getFps(); updatePhaseConfiguration(refreshRate); mRefreshRateStats->setRefreshRate(refreshRate); } @@ -2981,14 +3127,13 @@ void SurfaceFlinger::processDisplayChangesLocked() { mDrawingState.displays = mCurrentState.displays; } -void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { - // Commit display transactions +void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { + // Commit display transactions. const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; if (displayTransactionNeeded) { processDisplayChangesLocked(); processDisplayHotplugEventsLocked(); } - mForceTraversal = false; mForceTransactionDisplayChange = displayTransactionNeeded; if (mSomeChildrenChanged) { @@ -2996,18 +3141,9 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { mSomeChildrenChanged = false; } - // Update transform hint + // Update transform hint. if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) { - // The transform hint might have changed for some layers - // (either because a display has changed, or because a layer - // as changed). - // - // Walk through all the layers in currentLayers, - // and update their transform hint. - // - // If a layer is visible only on a single display, then that - // display is used to calculate the hint, otherwise we use the - // default display. + // Layers and/or displays have changed, so update the transform hint for each layer. // // NOTE: we do this here, rather than when presenting the display so that // the hint is set before we acquire a buffer from the surface texture. @@ -3018,30 +3154,29 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { // (soon to become the drawing state list). // sp<const DisplayDevice> hintDisplay; - uint32_t currentlayerStack = 0; - bool first = true; + ui::LayerStack layerStack; + mCurrentState.traverse([&](Layer* layer) REQUIRES(mStateLock) { // NOTE: we rely on the fact that layers are sorted by // layerStack first (so we don't have to traverse the list // of displays for every layer). - uint32_t layerStack = layer->getLayerStack(); - if (first || currentlayerStack != layerStack) { - currentlayerStack = layerStack; - // figure out if this layerstack is mirrored - // (more than one display) if so, pick the default display, - // if not, pick the only display it's on. + if (const auto filter = layer->getOutputFilter(); layerStack != filter.layerStack) { + layerStack = filter.layerStack; hintDisplay = nullptr; + + // Find the display that includes the layer. for (const auto& [token, display] : mDisplays) { - if (display->getCompositionDisplay() - ->belongsInOutput(layer->getLayerStack(), - layer->getPrimaryDisplayOnly())) { - if (hintDisplay) { - hintDisplay = nullptr; - break; - } else { - hintDisplay = display; - } + if (!display->getCompositionDisplay()->includesLayer(filter)) { + continue; + } + + // Pick the primary display if another display mirrors the layer. + if (hintDisplay) { + hintDisplay = nullptr; + break; } + + hintDisplay = display; } } @@ -3055,20 +3190,10 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { hintDisplay = getDefaultDisplayDeviceLocked(); } - // could be null if there is no display available at all to get - // the transform hint from. - if (hintDisplay) { - layer->updateTransformHint(hintDisplay->getTransformHint()); - } - - first = false; + layer->updateTransformHint(hintDisplay->getTransformHint()); }); } - /* - * Perform our own transaction if needed - */ - if (mLayersAdded) { mLayersAdded = false; // Layers have been added. @@ -3090,7 +3215,9 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { }); } - commitTransaction(); + doCommitTransactions(); + signalSynchronousTransactions(CountDownLatch::eSyncTransaction); + mAnimTransactionPending = false; } void SurfaceFlinger::updateInputFlinger() { @@ -3099,46 +3226,119 @@ void SurfaceFlinger::updateInputFlinger() { return; } + std::vector<WindowInfo> windowInfos; + std::vector<DisplayInfo> displayInfos; + bool updateWindowInfo = false; if (mVisibleRegionsDirty || mInputInfoChanged) { mInputInfoChanged = false; - notifyWindowInfos(); - } else if (mInputWindowCommands.syncInputWindows) { - // If the caller requested to sync input windows, but there are no - // changes to input windows, notify immediately. - windowInfosReported(); + updateWindowInfo = true; + buildWindowInfos(windowInfos, displayInfos); } - - for (const auto& focusRequest : mInputWindowCommands.focusRequests) { - mInputFlinger->setFocusedWindow(focusRequest); + if (!updateWindowInfo && mInputWindowCommands.empty()) { + return; } + BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo, + windowInfos = std::move(windowInfos), + displayInfos = std::move(displayInfos), + inputWindowCommands = + std::move(mInputWindowCommands), + inputFlinger = mInputFlinger, this]() { + ATRACE_NAME("BackgroundExecutor::updateInputFlinger"); + if (updateWindowInfo) { + mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, + inputWindowCommands.syncInputWindows); + } else if (inputWindowCommands.syncInputWindows) { + // If the caller requested to sync input windows, but there are no + // changes to input windows, notify immediately. + windowInfosReported(); + } + for (const auto& focusRequest : inputWindowCommands.focusRequests) { + inputFlinger->setFocusedWindow(focusRequest); + } + }}); + mInputWindowCommands.clear(); } -bool enablePerWindowInputRotation() { - static bool value = - android::base::GetBoolProperty("persist.debug.per_window_input_rotation", false); - return value; +void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) { + const bool supportsDisplayBrightnessCommand = getHwComposer().getComposer()->isSupported( + Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand); + if (!supportsDisplayBrightnessCommand) { + return; + } + + for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { + if (const auto brightness = display->getStagedBrightness(); brightness) { + if (!needsComposite) { + const status_t error = + getHwComposer() + .setDisplayBrightness(display->getPhysicalId(), *brightness, + display->getCompositionDisplay() + ->getState() + .displayBrightnessNits, + Hwc2::Composer::DisplayBrightnessOptions{ + .applyImmediately = true}) + .get(); + + ALOGE_IF(error != NO_ERROR, + "Error setting display brightness for display %s: %d (%s)", + display->getDebugName().c_str(), error, strerror(error)); + } + display->persistBrightness(needsComposite); + } + } } -void SurfaceFlinger::notifyWindowInfos() { - std::vector<WindowInfo> windowInfos; +void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos, + std::vector<DisplayInfo>& outDisplayInfos) { + ftl::SmallMap<ui::LayerStack, DisplayDevice::InputInfo, 4> displayInputInfos; + + for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { + const auto layerStack = display->getLayerStack(); + const auto info = display->getInputInfo(); + + const auto [it, emplaced] = displayInputInfos.try_emplace(layerStack, info); + if (emplaced) { + continue; + } + + // If the layer stack is mirrored on multiple displays, the first display that is configured + // to receive input takes precedence. + auto& otherInfo = it->second; + if (otherInfo.receivesInput) { + ALOGW_IF(display->receivesInput(), + "Multiple displays claim to accept input for the same layer stack: %u", + layerStack.id); + } else { + otherInfo = info; + } + } + + static size_t sNumWindowInfos = 0; + outWindowInfos.reserve(sNumWindowInfos); + sNumWindowInfos = 0; mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; - sp<DisplayDevice> display = enablePerWindowInputRotation() - ? ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)) - : nullptr; - // When calculating the screen bounds we ignore the transparent region since it may - // result in an unwanted offset. - windowInfos.push_back(layer->fillInputInfo(display)); + + // Do not create WindowInfos for windows on displays that cannot receive input. + if (const auto opt = displayInputInfos.get(layer->getLayerStack())) { + const auto& info = opt->get(); + outWindowInfos.push_back(layer->fillInputInfo(info.transform, info.isSecure)); + } }); - mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, - mInputWindowCommands.syncInputWindows); + + sNumWindowInfos = outWindowInfos.size(); + + outDisplayInfos.reserve(displayInputInfos.size()); + for (const auto& [_, info] : displayInputInfos) { + outDisplayInfos.push_back(info.info); + } } void SurfaceFlinger::updateCursorAsync() { compositionengine::CompositionRefreshArgs refreshArgs; - for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { if (HalDisplayId::tryCast(display->getId())) { refreshArgs.outputs.push_back(display->getCompositionDisplay()); } @@ -3147,13 +3347,25 @@ void SurfaceFlinger::updateCursorAsync() { mCompositionEngine->updateCursorAsync(refreshArgs); } -void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, Scheduler::ModeEvent event) { +void SurfaceFlinger::requestDisplayMode(DisplayModePtr mode, DisplayModeEvent event) { // If this is called from the main thread mStateLock must be locked before // Currently the only way to call this function from the main thread is from // Scheduler::chooseRefreshRateForContent ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); - changeRefreshRateLocked(refreshRate, event); + + const auto display = getDefaultDisplayDeviceLocked(); + if (!display || mBootStage != BootStage::FINISHED) { + return; + } + ATRACE_CALL(); + + if (!display->refreshRateConfigs().isModeAllowed(mode->getId())) { + ALOGV("Skipping disallowed mode %d", mode->getId().value()); + return; + } + + setDesiredActiveMode({std::move(mode), event}); } void SurfaceFlinger::triggerOnFrameRateOverridesChanged() { @@ -3181,8 +3393,35 @@ void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate); mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs()); - // start the EventThread - mScheduler = getFactory().createScheduler(display->holdRefreshRateConfigs(), *this); + using Feature = scheduler::Feature; + scheduler::FeatureFlags features; + + if (sysprop::use_content_detection_for_refresh_rate(false)) { + features |= Feature::kContentDetection; + } + if (base::GetBoolProperty("debug.sf.show_predicted_vsync"s, false)) { + features |= Feature::kTracePredictedVsync; + } + if (!base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false) && + !getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) { + features |= Feature::kPresentFences; + } + + mScheduler = std::make_unique<scheduler::Scheduler>(static_cast<ICompositor&>(*this), + static_cast<ISchedulerCallback&>(*this), + features); + { + auto configs = display->holdRefreshRateConfigs(); + if (configs->kernelIdleTimerController().has_value()) { + features |= Feature::kKernelIdleTimer; + } + + mScheduler->createVsyncSchedule(features); + mScheduler->setRefreshRateConfigs(std::move(configs)); + } + setVsyncEnabled(false); + mScheduler->startTimers(); + const auto configs = mVsyncConfiguration->getCurrentConfigs(); const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs(); mAppConnectionHandle = @@ -3198,8 +3437,8 @@ void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { mInterceptor->saveVSyncEvent(timestamp); }); - mEventQueue->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(), - configs.late.sfWorkDuration); + mScheduler->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(), + configs.late.sfWorkDuration); mRegionSamplingThread = new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables()); @@ -3212,11 +3451,6 @@ void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { // classes from EventThread, and there should be no run-time binder cost // anyway since there are no connected apps at this point. mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode()); - static auto ignorePresentFences = - base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false); - mScheduler->setIgnorePresentFences( - ignorePresentFences || - getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)); } void SurfaceFlinger::updatePhaseConfiguration(const Fps& refreshRate) { @@ -3233,27 +3467,29 @@ void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config, mScheduler->setDuration(mSfConnectionHandle, /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod), /*readyDuration=*/config.sfWorkDuration); - mEventQueue->setDuration(config.sfWorkDuration); + mScheduler->setDuration(config.sfWorkDuration); } -void SurfaceFlinger::commitTransaction() { +void SurfaceFlinger::doCommitTransactions() { ATRACE_CALL(); - commitTransactionLocked(); - signalSynchronousTransactions(CountDownLatch::eSyncTransaction); - mAnimTransactionPending = false; -} -void SurfaceFlinger::commitTransactionLocked() { if (!mLayersPendingRemoval.isEmpty()) { // Notify removed layers now that they can't be drawn from for (const auto& l : mLayersPendingRemoval) { - recordBufferingStats(l->getName(), l->getOccupancyHistory(true)); - // Ensure any buffers set to display on any children are released. if (l->isRemovedFromCurrentState()) { l->latchAndReleaseBuffer(); } + // If a layer has a parent, we allow it to out-live it's handle + // with the idea that the parent holds a reference and will eventually + // be cleaned up. However no one cleans up the top-level so we do so + // here. + if (l->isAtRoot()) { + l->setIsAtRoot(false); + mCurrentState.layersSortedByZ.remove(l); + } + // If the layer has been removed and has no parent, then it will not be reachable // when traversing layers on screen. Add the layer to the offscreenLayers set to // ensure we can copy its current to drawing state. @@ -3287,29 +3523,27 @@ void SurfaceFlinger::commitTransactionLocked() { void SurfaceFlinger::commitOffscreenLayers() { for (Layer* offscreenLayer : mOffscreenLayers) { offscreenLayer->traverse(LayerVector::StateSet::Drawing, [](Layer* layer) { - uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); - if (!trFlags) return; - - layer->doTransaction(0); - layer->commitChildList(); + if (layer->clearTransactionFlags(eTransactionNeeded)) { + layer->doTransaction(0); + layer->commitChildList(); + } }); } } void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) { - for (const auto& [token, displayDevice] : ON_MAIN_THREAD(mDisplays)) { + for (const auto& [token, displayDevice] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { auto display = displayDevice->getCompositionDisplay(); - if (display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { + if (display->includesLayer(layer->getOutputFilter())) { display->editState().dirtyRegion.orSelf(dirty); } } } -bool SurfaceFlinger::handlePageFlip() { +bool SurfaceFlinger::latchBuffers() { ATRACE_CALL(); - ALOGV("handlePageFlip"); - nsecs_t latchTime = systemTime(); + const nsecs_t latchTime = systemTime(); bool visibleRegions = false; bool frameQueued = false; @@ -3327,14 +3561,14 @@ bool SurfaceFlinger::handlePageFlip() { // Display is now waiting on Layer 1's frame, which is behind layer 0's // second frame. But layer 0's second frame could be waiting on display. mDrawingState.traverse([&](Layer* layer) { - uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); - if (trFlags || mForceTransactionDisplayChange) { - const uint32_t flags = layer->doTransaction(0); - if (flags & Layer::eVisibleRegion) - mVisibleRegionsDirty = true; - } + if (layer->clearTransactionFlags(eTransactionNeeded) || mForceTransactionDisplayChange) { + const uint32_t flags = layer->doTransaction(0); + if (flags & Layer::eVisibleRegion) { + mVisibleRegionsDirty = true; + } + } - if (layer->hasReadyFrame()) { + if (layer->hasReadyFrame()) { frameQueued = true; if (layer->shouldPresentNow(expectedPresentTime)) { mLayersWithQueuedFrames.emplace(layer); @@ -3342,7 +3576,7 @@ bool SurfaceFlinger::handlePageFlip() { ATRACE_NAME("!layer->shouldPresentNow()"); layer->useEmptyDamage(); } - } else { + } else { layer->useEmptyDamage(); } }); @@ -3364,11 +3598,9 @@ bool SurfaceFlinger::handlePageFlip() { for (const auto& layer : mLayersWithQueuedFrames) { if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) { mLayersPendingRefresh.push_back(layer); - } - layer->useSurfaceDamage(); - if (layer->isBufferLatched()) { newDataLatched = true; } + layer->useSurfaceDamage(); } } @@ -3378,7 +3610,7 @@ bool SurfaceFlinger::handlePageFlip() { // queued frame that shouldn't be displayed during this vsync period, wake // up during the next vsync period to check again. if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) { - signalLayerUpdate(); + scheduleCommit(FrameHint::kNone); } // enter boot animation on first buffer latch @@ -3395,164 +3627,279 @@ bool SurfaceFlinger::handlePageFlip() { return !mLayersWithQueuedFrames.empty() && newDataLatched; } -void SurfaceFlinger::invalidateHwcGeometry() { - mGeometryInvalid = true; -} - status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc, - const sp<IBinder>& parentHandle, - const sp<Layer>& parentLayer, bool addToRoot, - uint32_t* outTransformHint) { + const sp<Layer>& layer, const wp<Layer>& parent, + bool addToRoot, uint32_t* outTransformHint) { if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), ISurfaceComposer::MAX_LAYERS); + static_cast<void>(mScheduler->schedule([=] { + ALOGE("Dumping random sampling of on-screen layers: "); + mDrawingState.traverse([&](Layer *layer) { + // Aim to dump about 200 layers to avoid totally trashing + // logcat. On the other hand, if there really are 4096 layers + // something has gone totally wrong its probably the most + // useful information in logcat. + if (rand() % 20 == 13) { + ALOGE("Layer: %s", layer->getName().c_str()); + } + }); + for (Layer* offscreenLayer : mOffscreenLayers) { + if (rand() % 20 == 13) { + ALOGE("Offscreen-layer: %s", offscreenLayer->getName().c_str()); + } + } + })); return NO_MEMORY; } - wp<IBinder> initialProducer; - if (gbc != nullptr) { - initialProducer = IInterface::asBinder(gbc); + { + std::scoped_lock<std::mutex> lock(mCreatedLayersLock); + mCreatedLayers.emplace_back(layer, parent, addToRoot); } - setLayerCreatedState(handle, lbc, parentHandle, parentLayer, initialProducer, addToRoot); - // Create a transaction includes the initial parent and producer. - Vector<ComposerState> states; - Vector<DisplayState> displays; - - ComposerState composerState; - composerState.state.what = layer_state_t::eLayerCreated; - composerState.state.surface = handle; - states.add(composerState); - - lbc->updateTransformHint(mActiveDisplayTransformHint); + layer->updateTransformHint(mActiveDisplayTransformHint); if (outTransformHint) { *outTransformHint = mActiveDisplayTransformHint; } // attach this layer to the client - client->attachLayer(handle, lbc); - - return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr, - InputWindowCommands{}, -1 /* desiredPresentTime */, - true /* isAutoTimestamp */, {}, false /* hasListenerCallbacks */, {}, - 0 /* Undefined transactionId */); -} + if (client != nullptr) { + client->attachLayer(handle, layer); + } -void SurfaceFlinger::removeGraphicBufferProducerAsync(const wp<IBinder>& binder) { - static_cast<void>(schedule([=] { - Mutex::Autolock lock(mStateLock); - mGraphicBufferProducerList.erase(binder); - })); + setTransactionFlags(eTransactionNeeded); + return NO_ERROR; } -uint32_t SurfaceFlinger::peekTransactionFlags() { +uint32_t SurfaceFlinger::getTransactionFlags() const { return mTransactionFlags; } -uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) { - return mTransactionFlags.fetch_and(~flags) & flags; +uint32_t SurfaceFlinger::clearTransactionFlags(uint32_t mask) { + return mTransactionFlags.fetch_and(~mask) & mask; } -uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { - return setTransactionFlags(flags, TransactionSchedule::Late); +void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule, + const sp<IBinder>& applyToken, FrameHint frameHint) { + modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken); + + if (const bool scheduled = mTransactionFlags.fetch_or(mask) & mask; !scheduled) { + scheduleCommit(frameHint); + } } -uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule, - const sp<IBinder>& token) { - uint32_t old = mTransactionFlags.fetch_or(flags); - modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, token); - if ((old & flags) == 0) signalTransaction(); - return old; +bool SurfaceFlinger::stopTransactionProcessing( + const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& + applyTokensWithUnsignaledTransactions) const { + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) { + // if we are in LatchUnsignaledConfig::AutoSingleLayer + // then we should have only one applyToken for processing. + // so we can stop further transactions on this applyToken. + return !applyTokensWithUnsignaledTransactions.empty(); + } + + return false; } -void SurfaceFlinger::setTraversalNeeded() { - mForceTraversal = true; +int SurfaceFlinger::flushUnsignaledPendingTransactionQueues( + std::vector<TransactionState>& transactions, + std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, + std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions) { + return flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, + applyTokensWithUnsignaledTransactions, + /*tryApplyUnsignaled*/ true); +} + +int SurfaceFlinger::flushPendingTransactionQueues( + std::vector<TransactionState>& transactions, + std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, + std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions, + bool tryApplyUnsignaled) { + int transactionsPendingBarrier = 0; + auto it = mPendingTransactionQueues.begin(); + while (it != mPendingTransactionQueues.end()) { + auto& [applyToken, transactionQueue] = *it; + while (!transactionQueue.empty()) { + if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) { + ATRACE_NAME("stopTransactionProcessing"); + break; + } + + auto& transaction = transactionQueue.front(); + const auto ready = + transactionIsReadyToBeApplied(transaction, + transaction.frameTimelineInfo, + transaction.isAutoTimestamp, + transaction.desiredPresentTime, + transaction.originUid, transaction.states, + bufferLayersReadyToPresent, transactions.size(), + tryApplyUnsignaled); + ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); + if (ready == TransactionReadiness::NotReady) { + setTransactionFlags(eTransactionFlushNeeded); + break; + } + if (ready == TransactionReadiness::NotReadyBarrier) { + transactionsPendingBarrier++; + setTransactionFlags(eTransactionFlushNeeded); + break; + } + transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { + const bool frameNumberChanged = state.bufferData->flags.test( + BufferData::BufferDataChange::frameNumberChanged); + if (frameNumberChanged) { + bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber; + } else { + // Barrier function only used for BBQ which always includes a frame number + bufferLayersReadyToPresent[state.surface] = + std::numeric_limits<uint64_t>::max(); + } + }); + const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled); + if (appliedUnsignaled) { + applyTokensWithUnsignaledTransactions.insert(transaction.applyToken); + } + + transactions.emplace_back(std::move(transaction)); + transactionQueue.pop(); + } + + if (transactionQueue.empty()) { + it = mPendingTransactionQueues.erase(it); + mTransactionQueueCV.broadcast(); + } else { + it = std::next(it, 1); + } + } + return transactionsPendingBarrier; } -void SurfaceFlinger::flushTransactionQueues() { +bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { // to prevent onHandleDestroyed from being called while the lock is held, // we must keep a copy of the transactions (specifically the composer // states) around outside the scope of the lock - std::vector<const TransactionState> transactions; + std::vector<TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. - std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> bufferLayersReadyToPresent; + std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>> bufferLayersReadyToPresent; + std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions; { Mutex::Autolock _l(mStateLock); { Mutex::Autolock _l(mQueueLock); - // Collect transactions from pending transaction queue. - auto it = mPendingTransactionQueues.begin(); - while (it != mPendingTransactionQueues.end()) { - auto& [applyToken, transactionQueue] = *it; - - while (!transactionQueue.empty()) { - auto& transaction = transactionQueue.front(); - if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo, - transaction.isAutoTimestamp, - transaction.desiredPresentTime, - transaction.originUid, transaction.states, - bufferLayersReadyToPresent)) { - setTransactionFlags(eTransactionFlushNeeded); - break; - } - transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { - bufferLayersReadyToPresent.insert(state.surface); - }); - transactions.emplace_back(std::move(transaction)); - transactionQueue.pop(); - } - - if (transactionQueue.empty()) { - it = mPendingTransactionQueues.erase(it); - mTransactionQueueCV.broadcast(); - } else { - it = std::next(it, 1); - } - } - // Collect transactions from current transaction queue or queue to pending transactions. - // Case 1: push to pending when transactionIsReadyToBeApplied is false. - // Case 2: push to pending when there exist a pending queue. - // Case 3: others are ready to apply. + int lastTransactionsPendingBarrier = 0; + int transactionsPendingBarrier = 0; + // First collect transactions from the pending transaction queues. + // We are not allowing unsignaled buffers here as we want to + // collect all the transactions from applyTokens that are ready first. + transactionsPendingBarrier = + flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, + applyTokensWithUnsignaledTransactions, /*tryApplyUnsignaled*/ false); + + // Second, collect transactions from the transaction queue. + // Here as well we are not allowing unsignaled buffers for the same + // reason as above. while (!mTransactionQueue.empty()) { auto& transaction = mTransactionQueue.front(); - bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) != + const bool pendingTransactions = + mPendingTransactionQueues.find(transaction.applyToken) != mPendingTransactionQueues.end(); - if (pendingTransactions || - !transactionIsReadyToBeApplied(transaction.frameTimelineInfo, - transaction.isAutoTimestamp, - transaction.desiredPresentTime, - transaction.originUid, transaction.states, - bufferLayersReadyToPresent)) { + const auto ready = [&]() REQUIRES(mStateLock) { + if (pendingTransactions) { + ATRACE_NAME("pendingTransactions"); + return TransactionReadiness::NotReady; + } + + return transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo, + transaction.isAutoTimestamp, + transaction.desiredPresentTime, + transaction.originUid, transaction.states, + bufferLayersReadyToPresent, + transactions.size(), + /*tryApplyUnsignaled*/ false); + }(); + ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); + if (ready != TransactionReadiness::Ready) { + if (ready == TransactionReadiness::NotReadyBarrier) { + transactionsPendingBarrier++; + } mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); } else { transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { - bufferLayersReadyToPresent.insert(state.surface); + const bool frameNumberChanged = state.bufferData->flags.test( + BufferData::BufferDataChange::frameNumberChanged); + if (frameNumberChanged) { + bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber; + } else { + // Barrier function only used for BBQ which always includes a frame number. + // This value only used for barrier logic. + bufferLayersReadyToPresent[state.surface] = + std::numeric_limits<uint64_t>::max(); + } }); transactions.emplace_back(std::move(transaction)); } - mTransactionQueue.pop(); + mTransactionQueue.pop_front(); ATRACE_INT("TransactionQueue", mTransactionQueue.size()); } - } - // Now apply all transactions. - for (const auto& transaction : transactions) { - applyTransactionState(transaction.frameTimelineInfo, transaction.states, - transaction.displays, transaction.flags, - transaction.inputWindowCommands, transaction.desiredPresentTime, - transaction.isAutoTimestamp, transaction.buffer, - transaction.postTime, transaction.permissions, - transaction.hasListenerCallbacks, transaction.listenerCallbacks, - transaction.originPid, transaction.originUid, transaction.id); - if (transaction.transactionCommittedSignal) { - mTransactionCommittedSignals.emplace_back( - std::move(transaction.transactionCommittedSignal)); + // Transactions with a buffer pending on a barrier may be on a different applyToken + // than the transaction which satisfies our barrier. In fact this is the exact use case + // that the primitive is designed for. This means we may first process + // the barrier dependent transaction, determine it ineligible to complete + // and then satisfy in a later inner iteration of flushPendingTransactionQueues. + // The barrier dependent transaction was eligible to be presented in this frame + // but we would have prevented it without case. To fix this we continually + // loop through flushPendingTransactionQueues until we perform an iteration + // where the number of transactionsPendingBarrier doesn't change. This way + // we can continue to resolve dependency chains of barriers as far as possible. + while (lastTransactionsPendingBarrier != transactionsPendingBarrier) { + lastTransactionsPendingBarrier = transactionsPendingBarrier; + transactionsPendingBarrier = + flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, + applyTokensWithUnsignaledTransactions, + /*tryApplyUnsignaled*/ false); } + + // We collected all transactions that could apply without latching unsignaled buffers. + // If we are allowing latch unsignaled of some form, now it's the time to go over the + // transactions that were not applied and try to apply them unsignaled. + if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { + flushUnsignaledPendingTransactionQueues(transactions, bufferLayersReadyToPresent, + applyTokensWithUnsignaledTransactions); + } + + return applyTransactions(transactions, vsyncId); } } } +bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions, + int64_t vsyncId) { + bool needsTraversal = false; + // Now apply all transactions. + for (auto& transaction : transactions) { + needsTraversal |= + applyTransactionState(transaction.frameTimelineInfo, transaction.states, + transaction.displays, transaction.flags, + transaction.inputWindowCommands, + transaction.desiredPresentTime, transaction.isAutoTimestamp, + transaction.buffer, transaction.postTime, + transaction.permissions, transaction.hasListenerCallbacks, + transaction.listenerCallbacks, transaction.originPid, + transaction.originUid, transaction.id); + if (transaction.transactionCommittedSignal) { + mTransactionCommittedSignals.emplace_back( + std::move(transaction.transactionCommittedSignal)); + } + } + + if (mTransactionTracing) { + mTransactionTracing->addCommittedTransactions(transactions, vsyncId); + } + return needsTraversal; +} + bool SurfaceFlinger::transactionFlushNeeded() { Mutex::Autolock _l(mQueueLock); return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty(); @@ -3579,42 +3926,84 @@ bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) return prediction->presentTime >= expectedPresentTime && prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold; } +bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state, + size_t numStates, size_t totalTXapplied) const { + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { + ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__); + return false; + } + + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) { + ALOGV("%s: true (LatchUnsignaledConfig::Always)", __func__); + return true; + } + + // We only want to latch unsignaled when a single layer is updated in this + // transaction (i.e. not a blast sync transaction). + if (numStates != 1) { + ALOGV("%s: false (numStates=%zu)", __func__, numStates); + return false; + } + + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) { + if (totalTXapplied > 0) { + ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)", + __func__, totalTXapplied); + return false; + } + + // We don't want to latch unsignaled if are in early / client composition + // as it leads to jank due to RenderEngine waiting for unsignaled buffer + // or window animations being slow. + const auto isDefaultVsyncConfig = mVsyncModulator->isVsyncConfigDefault(); + if (!isDefaultVsyncConfig) { + ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; !isDefaultVsyncConfig)", + __func__); + return false; + } + } -bool SurfaceFlinger::transactionIsReadyToBeApplied( + if (!layer->simpleBufferUpdate(state)) { + ALOGV("%s: false (!simpleBufferUpdate)", __func__); + return false; + } + + ALOGV("%s: true", __func__); + return true; +} + +auto SurfaceFlinger::transactionIsReadyToBeApplied(TransactionState& transaction, const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, - const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& - bufferLayersReadyToPresent) const { - ATRACE_CALL(); + const std::unordered_map< + sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, + size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness { + ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId); const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Do not present if the desiredPresentTime has not passed unless it is more than one second // in the future. We ignore timestamps more than 1 second in the future for stability reasons. if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime && desiredPresentTime < expectedPresentTime + s2ns(1)) { ATRACE_NAME("not current"); - return false; + return TransactionReadiness::NotReady; } if (!mScheduler->isVsyncValid(expectedPresentTime, originUid)) { ATRACE_NAME("!isVsyncValid"); - return false; + return TransactionReadiness::NotReady; } // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected // present time of this transaction. if (isAutoTimestamp && frameIsEarly(expectedPresentTime, info.vsyncId)) { ATRACE_NAME("frameIsEarly"); - return false; + return TransactionReadiness::NotReady; } + bool fenceUnsignaled = false; + auto queueProcessTime = systemTime(); for (const ComposerState& state : states) { const layer_state_t& s = state.state; - const bool acquireFenceChanged = (s.what & layer_state_t::eAcquireFenceChanged); - if (acquireFenceChanged && s.acquireFence && !enableLatchUnsignaled && - s.acquireFence->getStatus() == Fence::Status::Unsignaled) { - ATRACE_NAME("fence unsignaled"); - return false; - } sp<Layer> layer = nullptr; if (s.surface) { @@ -3627,41 +4016,61 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( continue; } - ATRACE_NAME(layer->getName().c_str()); + if (s.hasBufferChanges() && s.bufferData->hasBarrier && + ((layer->getDrawingState().frameNumber) < s.bufferData->barrierFrameNumber)) { + const bool willApplyBarrierFrame = + (bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end()) && + (bufferLayersReadyToPresent.at(s.surface) >= s.bufferData->barrierFrameNumber); + if (!willApplyBarrierFrame) { + ATRACE_NAME("NotReadyBarrier"); + return TransactionReadiness::NotReadyBarrier; + } + } + + const bool allowLatchUnsignaled = tryApplyUnsignaled && + shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied); + ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(), + allowLatchUnsignaled ? "true" : "false"); + + const bool acquireFenceChanged = s.bufferData && + s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && + s.bufferData->acquireFence; + fenceUnsignaled = fenceUnsignaled || + (acquireFenceChanged && + s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled); + + if (fenceUnsignaled && !allowLatchUnsignaled) { + if (!transaction.sentFenceTimeoutWarning && + queueProcessTime - transaction.queueTime > std::chrono::nanoseconds(4s).count()) { + transaction.sentFenceTimeoutWarning = true; + auto listener = s.bufferData->releaseBufferListener; + if (listener) { + listener->onTransactionQueueStalled(); + } + } + + ATRACE_NAME("fence unsignaled"); + return TransactionReadiness::NotReady; + } if (s.hasBufferChanges()) { // If backpressure is enabled and we already have a buffer to commit, keep the // transaction in the queue. - const bool hasPendingBuffer = - bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end(); + const bool hasPendingBuffer = bufferLayersReadyToPresent.find(s.surface) != + bufferLayersReadyToPresent.end(); if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) { ATRACE_NAME("hasPendingBuffer"); - return false; + return TransactionReadiness::NotReady; } } } - return true; + return fenceUnsignaled ? TransactionReadiness::ReadyUnsignaled : TransactionReadiness::Ready; } void SurfaceFlinger::queueTransaction(TransactionState& state) { - Mutex::Autolock _l(mQueueLock); + state.queueTime = systemTime(); - // If its TransactionQueue already has a pending TransactionState or if it is pending - auto itr = mPendingTransactionQueues.find(state.applyToken); - // if this is an animation frame, wait until prior animation frame has - // been applied by SF - if (state.flags & eAnimation) { - while (itr != mPendingTransactionQueues.end()) { - status_t err = mTransactionQueueCV.waitRelative(mQueueLock, s2ns(5)); - if (CC_UNLIKELY(err != NO_ERROR)) { - ALOGW_IF(err == TIMED_OUT, - "setTransactionState timed out " - "waiting for animation frame to apply"); - break; - } - itr = mPendingTransactionQueues.find(state.applyToken); - } - } + Mutex::Autolock lock(mQueueLock); // Generate a CountDownLatch pending state if this is a synchronous transaction. if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) { @@ -3671,7 +4080,7 @@ void SurfaceFlinger::queueTransaction(TransactionState& state) { : CountDownLatch::eSyncTransaction)); } - mTransactionQueue.emplace(state); + mTransactionQueue.emplace_back(state); ATRACE_INT("TransactionQueue", mTransactionQueue.size()); const auto schedule = [](uint32_t flags) { @@ -3680,7 +4089,9 @@ void SurfaceFlinger::queueTransaction(TransactionState& state) { return TransactionSchedule::Late; }(state.flags); - setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken); + const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone; + + setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint); } void SurfaceFlinger::waitForSynchronousTransaction( @@ -3688,7 +4099,8 @@ void SurfaceFlinger::waitForSynchronousTransaction( // applyTransactionState is called on the main SF thread. While a given process may wish // to wait on synchronous transactions, the main SF thread should apply the transaction and // set the value to notify this after committed. - if (!transactionCommittedSignal.wait_until(std::chrono::seconds(5))) { + if (!transactionCommittedSignal.wait_until( + std::chrono::nanoseconds(mAnimationTransactionTimeout))) { ALOGE("setTransactionState timed out!"); } } @@ -3713,15 +4125,20 @@ status_t SurfaceFlinger::setTransactionState( ATRACE_CALL(); uint32_t permissions = - callingThreadHasUnscopedSurfaceFlingerAccess() ? Permission::ACCESS_SURFACE_FLINGER : 0; + callingThreadHasUnscopedSurfaceFlingerAccess() ? + layer_state_t::Permission::ACCESS_SURFACE_FLINGER : 0; // Avoid checking for rotation permissions if the caller already has ACCESS_SURFACE_FLINGER // permissions. - if ((permissions & Permission::ACCESS_SURFACE_FLINGER) || + if ((permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) || callingThreadHasRotateSurfaceFlingerAccess()) { - permissions |= Permission::ROTATE_SURFACE_FLINGER; + permissions |= layer_state_t::Permission::ROTATE_SURFACE_FLINGER; + } + + if (callingThreadHasInternalSystemWindowAccess()) { + permissions |= layer_state_t::Permission::INTERNAL_SYSTEM_WINDOW; } - if (!(permissions & Permission::ACCESS_SURFACE_FLINGER) && + if (!(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) && (flags & (eEarlyWakeupStart | eEarlyWakeupEnd))) { ALOGE("Only WindowManager is allowed to use eEarlyWakeup[Start|End] flags"); flags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd); @@ -3745,6 +4162,10 @@ status_t SurfaceFlinger::setTransactionState( state.traverseStatesWithBuffers([&](const layer_state_t& state) { mBufferCountTracker.increment(state.surface->localBinder()); }); + + if (mTransactionTracing) { + mTransactionTracing->addQueuedTransaction(state); + } queueTransaction(state); // Check the pending state to make sure the transaction is synchronous. @@ -3755,8 +4176,8 @@ status_t SurfaceFlinger::setTransactionState( return NO_ERROR; } -void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo, - const Vector<ComposerState>& states, +bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo, + Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, @@ -3774,36 +4195,27 @@ void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin // that listeners with SurfaceControls will start registration during setClientStateLocked // below. for (const auto& listener : listenerCallbacks) { - mTransactionCallbackInvoker.startRegistration(listener); - mTransactionCallbackInvoker.endRegistration(listener); + mTransactionCallbackInvoker.addEmptyTransaction(listener); } - std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> listenerCallbacksWithSurfaces; uint32_t clientStateFlags = 0; - for (const ComposerState& state : states) { - clientStateFlags |= - setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp, - postTime, permissions, listenerCallbacksWithSurfaces); + for (int i = 0; i < states.size(); i++) { + ComposerState& state = states.editItemAt(i); + clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, + isAutoTimestamp, postTime, permissions); if ((flags & eAnimation) && state.state.surface) { - if (const auto layer = fromHandle(state.state.surface).promote(); layer) { + if (const auto layer = fromHandle(state.state.surface).promote()) { + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; mScheduler->recordLayerHistory(layer.get(), isAutoTimestamp ? 0 : desiredPresentTime, - LayerHistory::LayerUpdateType::AnimationTX); + LayerUpdateType::AnimationTX); } } } - for (const auto& listenerCallback : listenerCallbacksWithSurfaces) { - mTransactionCallbackInvoker.endRegistration(listenerCallback); - } - - // If the state doesn't require a traversal and there are callbacks, send them now - if (!(clientStateFlags & eTraversalNeeded) && hasListenerCallbacks) { - mTransactionCallbackInvoker.sendCallbacks(); - } transactionFlags |= clientStateFlags; - if (permissions & Permission::ACCESS_SURFACE_FLINGER) { + if (permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) { transactionFlags |= addInputWindowCommands(inputWindowCommands); } else if (!inputWindowCommands.empty()) { ALOGE("Only privileged callers are allowed to send input commands."); @@ -3822,6 +4234,7 @@ void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin transactionFlags = eTransactionNeeded; } + bool needsTraversal = false; if (transactionFlags) { if (mInterceptor->isEnabled()) { mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags, @@ -3832,7 +4245,7 @@ void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin // so we don't have to wake up again next frame to preform an unnecessary traversal. if (transactionFlags & eTraversalNeeded) { transactionFlags = transactionFlags & (~eTraversalNeeded); - mForceTraversal = true; + needsTraversal = true; } if (transactionFlags) { setTransactionFlags(transactionFlags); @@ -3842,6 +4255,8 @@ void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin mAnimTransactionPending = true; } } + + return needsTraversal; } uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) { @@ -3910,12 +4325,12 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermis return true; } -uint32_t SurfaceFlinger::setClientStateLocked( - const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState, - int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions, - std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& outListenerCallbacks) { - const layer_state_t& s = composerState.state; - const bool privileged = permissions & Permission::ACCESS_SURFACE_FLINGER; +uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTimelineInfo, + ComposerState& composerState, + int64_t desiredPresentTime, bool isAutoTimestamp, + int64_t postTime, uint32_t permissions) { + layer_state_t& s = composerState.state; + s.sanitize(permissions); std::vector<ListenerCallbacks> filteredListeners; for (auto& listener : s.listeners) { @@ -3926,16 +4341,12 @@ uint32_t SurfaceFlinger::setClientStateLocked( ListenerCallbacks onCommitCallbacks = listener.filter(CallbackId::Type::ON_COMMIT); if (!onCommitCallbacks.callbackIds.empty()) { - mTransactionCallbackInvoker.startRegistration(onCommitCallbacks); filteredListeners.push_back(onCommitCallbacks); - outListenerCallbacks.insert(onCommitCallbacks); } ListenerCallbacks onCompleteCallbacks = listener.filter(CallbackId::Type::ON_COMPLETE); if (!onCompleteCallbacks.callbackIds.empty()) { - mTransactionCallbackInvoker.startRegistration(onCompleteCallbacks); filteredListeners.push_back(onCompleteCallbacks); - outListenerCallbacks.insert(onCompleteCallbacks); } } @@ -3943,15 +4354,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( uint32_t flags = 0; sp<Layer> layer = nullptr; if (s.surface) { - if (what & layer_state_t::eLayerCreated) { - layer = handleLayerCreatedLocked(s.surface); - if (layer) { - flags |= eTransactionNeeded | eTraversalNeeded; - mLayersAdded = true; - } - } else { - layer = fromHandle(s.surface).promote(); - } + layer = fromHandle(s.surface).promote(); } else { // The client may provide us a null handle. Treat it as if the layer was removed. ALOGW("Attempt to set client state with a null layer handle"); @@ -4037,36 +4440,14 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } if (what & layer_state_t::eMatrixChanged) { - // TODO: b/109894387 - // - // SurfaceFlinger's renderer is not prepared to handle cropping in the face of arbitrary - // rotation. To see the problem observe that if we have a square parent, and a child - // of the same size, then we rotate the child 45 degrees around it's center, the child - // must now be cropped to a non rectangular 8 sided region. - // - // Of course we can fix this in the future. For now, we are lucky, SurfaceControl is - // private API, and arbitrary rotation is used in limited use cases, for instance: - // - WindowManager only uses rotation in one case, which is on a top level layer in which - // cropping is not an issue. - // - Launcher, as a privileged app, uses this to transition an application to PiP - // (picture-in-picture) mode. - // - // However given that abuse of rotation matrices could lead to surfaces extending outside - // of cropped areas, we need to prevent non-root clients without permission - // ACCESS_SURFACE_FLINGER nor ROTATE_SURFACE_FLINGER - // (a.k.a. everyone except WindowManager / tests / Launcher) from setting non rectangle - // preserving transformations. - const bool allowNonRectPreservingTransforms = - permissions & Permission::ROTATE_SURFACE_FLINGER; - if (layer->setMatrix(s.matrix, allowNonRectPreservingTransforms)) flags |= eTraversalNeeded; + if (layer->setMatrix(s.matrix)) flags |= eTraversalNeeded; } if (what & layer_state_t::eTransparentRegionChanged) { if (layer->setTransparentRegionHint(s.transparentRegion)) flags |= eTraversalNeeded; } if (what & layer_state_t::eFlagsChanged) { - if (layer->setFlags(s.flags, s.mask)) - flags |= eTraversalNeeded; + if (layer->setFlags(s.flags, s.mask)) flags |= eTraversalNeeded; } if (what & layer_state_t::eCornerRadiusChanged) { if (layer->setCornerRadius(s.cornerRadius)) @@ -4108,9 +4489,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (what & layer_state_t::eCropChanged) { if (layer->setCrop(s.crop)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eAcquireFenceChanged) { - if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded; - } if (what & layer_state_t::eDataspaceChanged) { if (layer->setDataspace(s.dataspace)) flags |= eTraversalNeeded; } @@ -4127,23 +4505,20 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded; } if (what & layer_state_t::eInputInfoChanged) { - if (privileged) { - layer->setInputInfo(*s.windowInfoHandle->getInfo()); - flags |= eTraversalNeeded; - } else { - ALOGE("Attempt to update WindowInfo without permission ACCESS_SURFACE_FLINGER"); - } + layer->setInputInfo(*s.windowInfoHandle->getInfo()); + flags |= eTraversalNeeded; } std::optional<nsecs_t> dequeueBufferTimestamp; if (what & layer_state_t::eMetadataChanged) { dequeueBufferTimestamp = s.metadata.getInt64(METADATA_DEQUEUE_TIME); - auto gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1); - if (gameMode != -1) { + + if (const int32_t gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1); gameMode != -1) { // The transaction will be received on the Task layer and needs to be applied to all // child layers. Child layers that are added at a later point will obtain the game mode // info through addChild(). - layer->setGameModeForTree(gameMode); + layer->setGameModeForTree(static_cast<GameMode>(gameMode)); } + if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded; } if (what & layer_state_t::eColorSpaceAgnosticChanged) { @@ -4155,21 +4530,19 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setShadowRadius(s.shadowRadius)) flags |= eTraversalNeeded; } if (what & layer_state_t::eFrameRateSelectionPriority) { - if (privileged && layer->setFrameRateSelectionPriority(s.frameRateSelectionPriority)) { + if (layer->setFrameRateSelectionPriority(s.frameRateSelectionPriority)) { flags |= eTraversalNeeded; } } if (what & layer_state_t::eFrameRateChanged) { - if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility, s.changeFrameRateStrategy, - "SurfaceFlinger::setClientStateLocked", privileged)) { - const auto compatibility = - Layer::FrameRate::convertCompatibility(s.frameRateCompatibility); - const auto strategy = - Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy); + const auto compatibility = + Layer::FrameRate::convertCompatibility(s.frameRateCompatibility); + const auto strategy = + Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy); - if (layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), compatibility, strategy))) { - flags |= eTraversalNeeded; - } + if (layer->setFrameRate( + Layer::FrameRate(Fps::fromValue(s.frameRate), compatibility, strategy))) { + flags |= eTraversalNeeded; } } if (what & layer_state_t::eFixedTransformHintChanged) { @@ -4180,13 +4553,12 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (what & layer_state_t::eAutoRefreshChanged) { layer->setAutoRefresh(s.autoRefresh); } + if (what & layer_state_t::eDimmingEnabledChanged) { + if (layer->setDimmingEnabled(s.dimmingEnabled)) flags |= eTraversalNeeded; + } if (what & layer_state_t::eTrustedOverlayChanged) { - if (privileged) { - if (layer->setTrustedOverlay(s.isTrustedOverlay)) { - flags |= eTraversalNeeded; - } - } else { - ALOGE("Attempt to set trusted overlay without permission ACCESS_SURFACE_FLINGER"); + if (layer->setTrustedOverlay(s.isTrustedOverlay)) { + flags |= eTraversalNeeded; } } if (what & layer_state_t::eStretchChanged) { @@ -4205,13 +4577,9 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } if (what & layer_state_t::eDropInputModeChanged) { - if (privileged) { - if (layer->setDropInputMode(s.dropInputMode)) { - flags |= eTraversalNeeded; - mInputInfoChanged = true; - } - } else { - ALOGE("Attempt to update InputPolicyFlags without permission ACCESS_SURFACE_FLINGER"); + if (layer->setDropInputMode(s.dropInputMode)) { + flags |= eTraversalNeeded; + mInputInfoChanged = true; } } // This has to happen after we reparent children because when we reparent to null we remove @@ -4237,41 +4605,12 @@ uint32_t SurfaceFlinger::setClientStateLocked( callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); } } - bool bufferChanged = what & layer_state_t::eBufferChanged; - bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged; - bool bufferSizeExceedsLimit = false; - std::shared_ptr<renderengine::ExternalTexture> buffer; - if (bufferChanged && cacheIdChanged && s.buffer != nullptr) { - bufferSizeExceedsLimit = - exceedsMaxRenderTargetSize(s.buffer->getWidth(), s.buffer->getHeight()); - if (!bufferSizeExceedsLimit) { - ClientCache::getInstance().add(s.cachedBuffer, s.buffer); - buffer = ClientCache::getInstance().get(s.cachedBuffer); - } - } else if (cacheIdChanged) { - buffer = ClientCache::getInstance().get(s.cachedBuffer); - } else if (bufferChanged && s.buffer != nullptr) { - bufferSizeExceedsLimit = - exceedsMaxRenderTargetSize(s.buffer->getWidth(), s.buffer->getHeight()); - if (!bufferSizeExceedsLimit) { - buffer = std::make_shared< - renderengine::ExternalTexture>(s.buffer, getRenderEngine(), - renderengine::ExternalTexture::Usage::READABLE); - } - } - ALOGE_IF(bufferSizeExceedsLimit, - "Attempted to create an ExternalTexture for layer %s that exceeds render target size " - "limit.", - layer->getDebugName()); - if (buffer) { - const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged; - const uint64_t frameNumber = frameNumberChanged - ? s.frameNumber - : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1; - - if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp, - s.cachedBuffer, frameNumber, dequeueBufferTimestamp, frameTimelineInfo, - s.releaseBufferListener, s.releaseBufferEndpoint)) { + + if (what & layer_state_t::eBufferChanged) { + std::shared_ptr<renderengine::ExternalTexture> buffer = + getExternalTextureFromBufferData(*s.bufferData, layer->getDebugName()); + if (layer->setBuffer(buffer, *s.bufferData, postTime, desiredPresentTime, isAutoTimestamp, + dequeueBufferTimestamp, frameTimelineInfo)) { flags |= eTraversalNeeded; } } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { @@ -4289,25 +4628,22 @@ uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& input return hasChanges ? eTraversalNeeded : 0; } -status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle, - sp<IBinder>* outHandle, int32_t* outLayerId) { +status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args, + const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle, + int32_t* outLayerId) { if (!mirrorFromHandle) { return NAME_NOT_FOUND; } sp<Layer> mirrorLayer; sp<Layer> mirrorFrom; - std::string uniqueName = getUniqueLayerName("MirrorRoot"); - { Mutex::Autolock _l(mStateLock); mirrorFrom = fromHandle(mirrorFromHandle).promote(); if (!mirrorFrom) { return NAME_NOT_FOUND; } - - status_t result = createContainerLayer(client, std::move(uniqueName), -1, -1, 0, - LayerMetadata(), outHandle, &mirrorLayer); + status_t result = createContainerLayer(args, outHandle, &mirrorLayer); if (result != NO_ERROR) { return result; } @@ -4316,22 +4652,17 @@ status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder> } *outLayerId = mirrorLayer->sequence; - return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false, - nullptr /* outTransformHint */); + if (mTransactionTracing) { + mTransactionTracing->onMirrorLayerAdded((*outHandle)->localBinder(), mirrorLayer->sequence, + args.name, mirrorFrom->sequence); + } + return addClientLayer(args.client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */, + false /* addToRoot */, nullptr /* outTransformHint */); } -status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w, - uint32_t h, PixelFormat format, uint32_t flags, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, +status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle, const sp<IBinder>& parentHandle, int32_t* outLayerId, const sp<Layer>& parentLayer, uint32_t* outTransformHint) { - if (int32_t(w|h) < 0) { - ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)", - int(w), int(h)); - return BAD_VALUE; - } - ALOG_ASSERT(parentLayer == nullptr || parentHandle == nullptr, "Expected only one of parentLayer or parentHandle to be non-null. " "Programmer error?"); @@ -4340,40 +4671,22 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& clie sp<Layer> layer; - std::string uniqueName = getUniqueLayerName(name.string()); - - switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { + switch (args.flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: case ISurfaceComposerClient::eFXSurfaceBufferState: { - result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags, - std::move(metadata), handle, &layer); + result = createBufferStateLayer(args, outHandle, &layer); std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter(); if (pendingBufferCounter) { std::string counterName = layer->getPendingBufferCounterName(); - mBufferCountTracker.add((*handle)->localBinder(), counterName, + mBufferCountTracker.add((*outHandle)->localBinder(), counterName, pendingBufferCounter); } } break; case ISurfaceComposerClient::eFXSurfaceEffect: - // check if buffer size is set for color layer. - if (w > 0 || h > 0) { - ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)", - int(w), int(h)); - return BAD_VALUE; - } - - result = createEffectLayer(client, std::move(uniqueName), w, h, flags, - std::move(metadata), handle, &layer); + result = createEffectLayer(args, outHandle, &layer); break; case ISurfaceComposerClient::eFXSurfaceContainer: - // check if buffer size is set for container layer. - if (w > 0 || h > 0) { - ALOGE("createLayer() failed, w or h cannot be set for container layer (w=%d, h=%d)", - int(w), int(h)); - return BAD_VALUE; - } - result = createContainerLayer(client, std::move(uniqueName), w, h, flags, - std::move(metadata), handle, &layer); + result = createContainerLayer(args, outHandle, &layer); break; default: result = BAD_VALUE; @@ -4384,47 +4697,38 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& clie return result; } - bool addToRoot = callingThreadHasUnscopedSurfaceFlingerAccess(); - result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer, addToRoot, - outTransformHint); + bool addToRoot = args.addToRoot && callingThreadHasUnscopedSurfaceFlingerAccess(); + wp<Layer> parent(parentHandle != nullptr ? fromHandle(parentHandle) : parentLayer); + if (parentHandle != nullptr && parent == nullptr) { + ALOGE("Invalid parent handle %p.", parentHandle.get()); + addToRoot = false; + } + if (parentLayer != nullptr) { + addToRoot = false; + } + + int parentId = -1; + // We can safely promote the layer in binder thread because we have a strong reference + // to the layer's handle inside this scope or we were passed in a sp reference to the layer. + sp<Layer> parentSp = parent.promote(); + if (parentSp != nullptr) { + parentId = parentSp->getSequence(); + } + if (mTransactionTracing) { + mTransactionTracing->onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name, + args.flags, parentId); + } + + result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint); if (result != NO_ERROR) { return result; } - mInterceptor->saveSurfaceCreation(layer); - setTransactionFlags(eTransactionNeeded); *outLayerId = layer->sequence; return result; } -std::string SurfaceFlinger::getUniqueLayerName(const char* name) { - unsigned dupeCounter = 0; - - // Tack on our counter whether there is a hit or not, so everyone gets a tag - std::string uniqueName = base::StringPrintf("%s#%u", name, dupeCounter); - - // Grab the state lock since we're accessing mCurrentState - Mutex::Autolock lock(mStateLock); - - // Loop over layers until we're sure there is no matching name - bool matchFound = true; - while (matchFound) { - matchFound = false; - mCurrentState.traverse([&](Layer* layer) { - if (layer->getName() == uniqueName) { - matchFound = true; - uniqueName = base::StringPrintf("%s#%u", name, ++dupeCounter); - } - }); - } - - ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name, uniqueName.c_str()); - return uniqueName; -} - -status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, - LayerMetadata metadata, PixelFormat& format, +status_t SurfaceFlinger::createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) { @@ -4440,7 +4744,6 @@ status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::s } sp<BufferQueueLayer> layer; - LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata)); args.textureName = getNewTexture(); { // Grab the SF state lock during this since it's the only safe way to access @@ -4450,7 +4753,7 @@ status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::s layer = getFactory().createBufferQueueLayer(args); } - status_t err = layer->setDefaultBufferProperties(w, h, format); + status_t err = layer->setDefaultBufferProperties(0, 0, format); if (err == NO_ERROR) { *handle = layer->getHandle(); *gbp = layer->getProducer(); @@ -4461,34 +4764,24 @@ status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::s return err; } -status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, - LayerMetadata metadata, sp<IBinder>* handle, +status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* handle, sp<Layer>* outLayer) { - LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata)); args.textureName = getNewTexture(); - sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(args); - *handle = layer->getHandle(); - *outLayer = layer; - + *outLayer = getFactory().createBufferStateLayer(args); + *handle = (*outLayer)->getHandle(); return NO_ERROR; } -status_t SurfaceFlinger::createEffectLayer(const sp<Client>& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - sp<IBinder>* handle, sp<Layer>* outLayer) { - *outLayer = getFactory().createEffectLayer( - {this, client, std::move(name), w, h, flags, std::move(metadata)}); +status_t SurfaceFlinger::createEffectLayer(const LayerCreationArgs& args, sp<IBinder>* handle, + sp<Layer>* outLayer) { + *outLayer = getFactory().createEffectLayer(args); *handle = (*outLayer)->getHandle(); return NO_ERROR; } -status_t SurfaceFlinger::createContainerLayer(const sp<Client>& client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, - LayerMetadata metadata, sp<IBinder>* handle, +status_t SurfaceFlinger::createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* handle, sp<Layer>* outLayer) { - *outLayer = getFactory().createContainerLayer( - {this, client, std::move(name), w, h, flags, std::move(metadata)}); + *outLayer = getFactory().createContainerLayer(args); *handle = (*outLayer)->getHandle(); return NO_ERROR; } @@ -4501,17 +4794,12 @@ void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) { void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer) { Mutex::Autolock lock(mStateLock); - // If a layer has a parent, we allow it to out-live it's handle - // with the idea that the parent holds a reference and will eventually - // be cleaned up. However no one cleans up the top-level so we do so - // here. - if (layer->isAtRoot()) { - layer->setIsAtRoot(false); - mCurrentState.layersSortedByZ.remove(layer); - } markLayerPendingRemovalLocked(layer); mBufferCountTracker.remove(handle); layer.clear(); + if (mTransactionTracing) { + mTransactionTracing->onHandleRemoved(handle); + } } // --------------------------------------------------------------------------- @@ -4530,7 +4818,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.what = DisplayState::eDisplayProjectionChanged | DisplayState::eLayerStackChanged; d.token = token; - d.layerStack = 0; + d.layerStack = ui::DEFAULT_LAYER_STACK; d.orientation = ui::ROTATION_0; d.orientedDisplaySpaceRect.makeInvalid(); d.layerStackSpaceRect.makeInvalid(); @@ -4539,14 +4827,15 @@ void SurfaceFlinger::onInitializeDisplays() { displays.add(d); nsecs_t now = systemTime(); + + int64_t transactionId = (((int64_t)mPid) << 32) | mUniqueTransactionId++; // It should be on the main thread, apply it directly. applyTransactionState(FrameTimelineInfo{}, state, displays, 0, mInputWindowCommands, /* desiredPresentTime */ now, true, {}, /* postTime */ now, true, false, - {}, getpid(), getuid(), 0 /* Undefined transactionId */); + {}, mPid, getuid(), transactionId); setPowerModeInternal(display, hal::PowerMode::ON); - const nsecs_t vsyncPeriod = - display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod(); + const nsecs_t vsyncPeriod = display->refreshRateConfigs().getActiveMode()->getVsyncPeriod(); mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod); mActiveDisplayTransformHint = display->getTransformHint(); // Use phase of 0 since phase is not known. @@ -4557,32 +4846,13 @@ void SurfaceFlinger::onInitializeDisplays() { void SurfaceFlinger::initializeDisplays() { // Async since we may be called from the main thread. - static_cast<void>(schedule([this]() MAIN_THREAD { onInitializeDisplays(); })); -} - -sp<DisplayDevice> SurfaceFlinger::getDisplayWithInputByLayer(Layer* layer) const { - sp<DisplayDevice> display; - for (const auto& pair : mDisplays) { - const auto& displayDevice = pair.second; - if (!displayDevice->receivesInput() || - !displayDevice->getCompositionDisplay() - ->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { - continue; - } - // Don't return immediately so that we can log duplicates. - if (display) { - ALOGE("Multiple display devices claim to accept input for the same layerstack: %d", - layer->getLayerStack()); - continue; - } - display = displayDevice; - } - return display; + static_cast<void>( + mScheduler->schedule([this]() FTL_FAKE_GUARD(mStateLock) { onInitializeDisplays(); })); } void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) { if (display->isVirtual()) { - ALOGE("%s: Invalid operation on virtual display", __FUNCTION__); + ALOGE("%s: Invalid operation on virtual display", __func__); return; } @@ -4605,7 +4875,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: if (mInterceptor->isEnabled()) { mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode)); } - const auto vsyncPeriod = display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod(); + const auto refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); if (currentMode == hal::PowerMode::OFF) { // Turn on the display if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) { @@ -4623,12 +4893,12 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: if (isDisplayActiveLocked(display) && mode != hal::PowerMode::DOZE_SUSPEND) { setHWCVsyncEnabled(displayId, mHWCVsyncPendingState); mScheduler->onScreenAcquired(mAppConnectionHandle); - mScheduler->resyncToHardwareVsync(true, vsyncPeriod); + mScheduler->resyncToHardwareVsync(true, refreshRate); } mVisibleRegionsDirty = true; mHasPoweredOff = true; - repaintEverything(); + scheduleComposite(FrameHint::kActive); } else if (mode == hal::PowerMode::OFF) { // Turn off the display if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) { @@ -4653,7 +4923,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: getHwComposer().setPowerMode(displayId, mode); if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) { mScheduler->onScreenAcquired(mAppConnectionHandle); - mScheduler->resyncToHardwareVsync(true, vsyncPeriod); + mScheduler->resyncToHardwareVsync(true, refreshRate); } } else if (mode == hal::PowerMode::DOZE_SUSPEND) { // Leave display going to doze @@ -4677,7 +4947,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) { - schedule([=]() MAIN_THREAD { + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set power mode %d for invalid display token %p", mode, @@ -4687,7 +4957,9 @@ void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) { } else { setPowerModeInternal(display, static_cast<hal::PowerMode>(mode)); } - }).wait(); + }); + + future.wait(); } status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { @@ -4703,10 +4975,11 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { pid, uid); } else { static const std::unordered_map<std::string, Dumper> dumpers = { + {"--comp-displays"s, dumper(&SurfaceFlinger::dumpCompositionDisplays)}, {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)}, + {"--displays"s, dumper(&SurfaceFlinger::dumpDisplays)}, {"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVsync(s); })}, {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)}, - {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)}, {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)}, {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)}, {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)}, @@ -4722,7 +4995,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { bool dumpLayers = true; { - TimedLock lock(mStateLock, s2ns(1), __FUNCTION__); + TimedLock lock(mStateLock, s2ns(1), __func__); if (!lock.locked()) { StringAppendF(&result, "Dumping without lock after timeout: %s (%d)\n", strerror(-lock.status), lock.status); @@ -4737,7 +5010,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } if (dumpLayers) { - LayersTraceFileProto traceFileProto = SurfaceTracing::createLayersTraceFileProto(); + LayersTraceFileProto traceFileProto = mLayerTracing.createTraceFileProto(); LayersTraceProto* layersTrace = traceFileProto.add_entry(); LayersProto layersProto = dumpProtoFromMainThread(); layersTrace->mutable_layers()->Swap(&layersProto); @@ -4759,8 +5032,11 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) { - if (asProto && mTracing.isEnabled()) { - mTracing.writeToFile(); + if (asProto) { + mLayerTracing.writeToFile(); + if (mTransactionTracing) { + mTransactionTracing->writeToFile(); + } } return doDump(fd, DumpArgs(), asProto); @@ -4807,8 +5083,6 @@ void SurfaceFlinger::dumpFrameTimeline(const DumpArgs& args, std::string& result mFrameTimeline->parseArgs(args, result); } -// This should only be called from the main thread. Otherwise it would need -// the lock and should use mCurrentState rather than mDrawingState. void SurfaceFlinger::logFrameStats() { mDrawingState.traverse([&](Layer* layer) { layer->logFrameStats(); @@ -4872,61 +5146,18 @@ void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const { bucketTimeSec, percent); } -void SurfaceFlinger::recordBufferingStats(const std::string& layerName, - std::vector<OccupancyTracker::Segment>&& history) { - Mutex::Autolock lock(getBE().mBufferingStatsMutex); - auto& stats = getBE().mBufferingStats[layerName]; - for (const auto& segment : history) { - if (!segment.usedThirdBuffer) { - stats.twoBufferTime += segment.totalTime; - } - if (segment.occupancyAverage < 1.0f) { - stats.doubleBufferedTime += segment.totalTime; - } else if (segment.occupancyAverage < 2.0f) { - stats.tripleBufferedTime += segment.totalTime; - } - ++stats.numSegments; - stats.totalTime += segment.totalTime; +void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const { + for (const auto& [token, display] : mDisplays) { + display->getCompositionDisplay()->dump(result); + result += '\n'; } } -void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) { - result.append("Layer frame timestamps:\n"); - // Traverse all layers to dump frame-events for each layer - mCurrentState.traverseInZOrder( - [&] (Layer* layer) { layer->dumpFrameEvents(result); }); -} - -void SurfaceFlinger::dumpBufferingStats(std::string& result) const { - result.append("Buffering stats:\n"); - result.append(" [Layer name] <Active time> <Two buffer> " - "<Double buffered> <Triple buffered>\n"); - Mutex::Autolock lock(getBE().mBufferingStatsMutex); - typedef std::tuple<std::string, float, float, float> BufferTuple; - std::map<float, BufferTuple, std::greater<float>> sorted; - for (const auto& statsPair : getBE().mBufferingStats) { - const char* name = statsPair.first.c_str(); - const SurfaceFlingerBE::BufferingStats& stats = statsPair.second; - if (stats.numSegments == 0) { - continue; - } - float activeTime = ns2ms(stats.totalTime) / 1000.0f; - float twoBufferRatio = static_cast<float>(stats.twoBufferTime) / - stats.totalTime; - float doubleBufferRatio = static_cast<float>( - stats.doubleBufferedTime) / stats.totalTime; - float tripleBufferRatio = static_cast<float>( - stats.tripleBufferedTime) / stats.totalTime; - sorted.insert({activeTime, {name, twoBufferRatio, - doubleBufferRatio, tripleBufferRatio}}); - } - for (const auto& sortedPair : sorted) { - float activeTime = sortedPair.first; - const BufferTuple& values = sortedPair.second; - StringAppendF(&result, " [%s] %.2f %.3f %.3f %.3f\n", std::get<0>(values).c_str(), - activeTime, std::get<1>(values), std::get<2>(values), std::get<3>(values)); +void SurfaceFlinger::dumpDisplays(std::string& result) const { + for (const auto& [token, display] : mDisplays) { + display->dump(result); + result += '\n'; } - result.append("\n"); } void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { @@ -5007,23 +5238,20 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { } LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { - // If context is SurfaceTracing thread, mTracingLock blocks display transactions on main thread. - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - LayersProto layersProto; for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) { - layer->writeToProto(layersProto, traceFlags, display.get()); + layer->writeToProto(layersProto, traceFlags); } return layersProto; } void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const { - for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { DisplayProto* displayProto = layersTraceProto.add_displays(); displayProto->set_id(display->getId().value); displayProto->set_name(display->getDisplayName()); - displayProto->set_layer_stack(display->getLayerStack()); + displayProto->set_layer_stack(display->getLayerStack().id); LayerProtoHelper::writeSizeToProto(display->getWidth(), display->getHeight(), [&]() { return displayProto->mutable_size(); }); LayerProtoHelper::writeToProto(display->getLayerStackSpaceRect(), [&]() { @@ -5031,6 +5259,7 @@ void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const }); LayerProtoHelper::writeTransformToProto(display->getTransform(), displayProto->mutable_transform()); + displayProto->set_is_virtual(display->isVirtual()); } } @@ -5052,28 +5281,27 @@ void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t rootProto->add_children(offscreenLayer->sequence); // Add layer - LayerProto* layerProto = - offscreenLayer->writeToProto(layersProto, traceFlags, nullptr /*device*/); + LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags); layerProto->set_parent(offscreenRootLayerId); } } LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) { - return schedule([=] { return dumpDrawingStateProto(traceFlags); }).get(); + return mScheduler->schedule([=] { return dumpDrawingStateProto(traceFlags); }).get(); } void SurfaceFlinger::dumpOffscreenLayers(std::string& result) { + auto future = mScheduler->schedule([this] { + std::string result; + for (Layer* offscreenLayer : mOffscreenLayers) { + offscreenLayer->traverse(LayerVector::StateSet::Drawing, + [&](Layer* layer) { layer->dumpCallingUidPid(result); }); + } + return result; + }); + result.append("Offscreen Layers:\n"); - result.append(schedule([this] { - std::string result; - for (Layer* offscreenLayer : mOffscreenLayers) { - offscreenLayer->traverse(LayerVector::StateSet::Drawing, - [&](Layer* layer) { - layer->dumpCallingUidPid(result); - }); - } - return result; - }).get()); + result.append(future.get()); } void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const { @@ -5120,15 +5348,11 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co StringAppendF(&result, "HWC missed frame count: %u\n", mHwcFrameMissedCount.load()); StringAppendF(&result, "GPU missed frame count: %u\n\n", mGpuFrameMissedCount.load()); - dumpBufferingStats(result); - /* * Dump the visible layer list */ colorizer.bold(result); StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load()); - StringAppendF(&result, "GraphicBufferProducers: %zu, max %zu\n", - mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize); colorizer.reset(result); { @@ -5144,21 +5368,12 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co }); } - /* - * Dump Display state - */ - colorizer.bold(result); StringAppendF(&result, "Displays (%zu entries)\n", mDisplays.size()); colorizer.reset(result); - for (const auto& [token, display] : mDisplays) { - display->dump(result); - } - result.append("\n"); - - /* - * Dump CompositionEngine state - */ + dumpDisplays(result); + dumpCompositionDisplays(result); + result.push_back('\n'); mCompositionEngine->dump(result); @@ -5191,8 +5406,10 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co std::string fps, xDpi, yDpi; if (const auto activeMode = display->getActiveMode()) { fps = to_string(activeMode->getFps()); - xDpi = base::StringPrintf("%.2f", activeMode->getDpiX()); - yDpi = base::StringPrintf("%.2f", activeMode->getDpiY()); + + const auto dpi = activeMode->getDpi(); + xDpi = base::StringPrintf("%.2f", dpi.x); + yDpi = base::StringPrintf("%.2f", dpi.y); } else { fps = "unknown"; xDpi = "unknown"; @@ -5210,8 +5427,16 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co /* * Tracing state */ - mTracing.dump(result); - result.append("\n"); + mLayerTracing.dump(result); + + result.append("\nTransaction tracing: "); + if (mTransactionTracing) { + result.append("enabled\n"); + mTransactionTracing->dump(result); + } else { + result.append("disabled\n"); + } + result.push_back('\n'); /* * HWC layer minidump @@ -5244,9 +5469,9 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co colorizer.bold(result); result.append("h/w composer state:\n"); colorizer.reset(result); - bool hwcDisabled = mDebugDisableHWC || mDebugRegion; + const bool hwcDisabled = mDebugDisableHWC || mDebugFlashDelay; StringAppendF(&result, " h/w composer %s\n", hwcDisabled ? "disabled" : "enabled"); - getHwComposer().dump(result); + dumpHwc(result); /* * Dump gralloc state @@ -5254,6 +5479,11 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); alloc.dump(result); + /* + * Dump flag/property manager state + */ + mFlagManager.dump(result); + result.append(mTimeStats->miniDump()); result.append("\n"); } @@ -5295,33 +5525,25 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // access to SF. case BOOT_FINISHED: case CLEAR_ANIMATION_FRAME_STATS: - case CREATE_DISPLAY: - case DESTROY_DISPLAY: case GET_ANIMATION_FRAME_STATS: case OVERRIDE_HDR_TYPES: case GET_HDR_CAPABILITIES: case SET_DESIRED_DISPLAY_MODE_SPECS: case GET_DESIRED_DISPLAY_MODE_SPECS: case SET_ACTIVE_COLOR_MODE: + case SET_BOOT_DISPLAY_MODE: case GET_AUTO_LOW_LATENCY_MODE_SUPPORT: - case SET_AUTO_LOW_LATENCY_MODE: case GET_GAME_CONTENT_TYPE_SUPPORT: - case SET_GAME_CONTENT_TYPE: - case SET_POWER_MODE: case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: case GET_DISPLAYED_CONTENT_SAMPLE: case ADD_TUNNEL_MODE_ENABLED_LISTENER: case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: - case NOTIFY_POWER_BOOST: case SET_GLOBAL_SHADOW_SETTINGS: - case GET_PRIMARY_PHYSICAL_DISPLAY_ID: case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { - // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN and OVERRIDE_HDR_TYPES are used by CTS tests, - // which acquire the necessary permission dynamically. Don't use the permission cache - // for this check. - bool usePermissionCache = - code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN && code != OVERRIDE_HDR_TYPES; + // OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary + // permission dynamically. Don't use the permission cache for this check. + bool usePermissionCache = code != OVERRIDE_HDR_TYPES; if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", @@ -5348,15 +5570,11 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case AUTHENTICATE_SURFACE: case GET_ACTIVE_COLOR_MODE: case GET_ACTIVE_DISPLAY_MODE: - case GET_PHYSICAL_DISPLAY_IDS: - case GET_PHYSICAL_DISPLAY_TOKEN: case GET_DISPLAY_COLOR_MODES: case GET_DISPLAY_NATIVE_PRIMARIES: case GET_STATIC_DISPLAY_INFO: case GET_DYNAMIC_DISPLAY_INFO: case GET_DISPLAY_MODES: - case GET_DISPLAY_STATE: - case GET_DISPLAY_STATS: case GET_SUPPORTED_FRAME_TIMESTAMPS: // Calling setTransactionState is safe, because you need to have been // granted a reference to Client* and Handle* to do anything with it. @@ -5365,33 +5583,16 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_COLOR_MANAGEMENT: case GET_COMPOSITION_PREFERENCE: case GET_PROTECTED_CONTENT_SUPPORT: - case IS_WIDE_COLOR_DISPLAY: // setFrameRate() is deliberately available for apps to call without any // special permissions. case SET_FRAME_RATE: - case GET_DISPLAY_BRIGHTNESS_SUPPORT: - // captureLayers and captureDisplay will handle the permission check in the function - case CAPTURE_LAYERS: - case CAPTURE_DISPLAY: + case GET_DISPLAY_DECORATION_SUPPORT: case SET_FRAME_TIMELINE_INFO: case GET_GPU_CONTEXT_PRIORITY: case GET_MAX_ACQUIRED_BUFFER_COUNT: { // This is not sensitive information, so should not require permission control. return OK; } - case SET_DISPLAY_BRIGHTNESS: - case ADD_HDR_LAYER_INFO_LISTENER: - case REMOVE_HDR_LAYER_INFO_LISTENER: { - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && - !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) { - ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - return OK; - } case ADD_FPS_LISTENER: case REMOVE_FPS_LISTENER: case ADD_REGION_SAMPLING_LISTENER: @@ -5407,8 +5608,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return OK; } - case ADD_TRANSACTION_TRACE_LISTENER: - case CAPTURE_DISPLAY_BY_ID: { + case ADD_TRANSACTION_TRACE_LISTENER: { IPCThreadState* ipc = IPCThreadState::self(); const int uid = ipc->getCallingUid(); if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { @@ -5416,6 +5616,13 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return PERMISSION_DENIED; } + case SET_OVERRIDE_FRAME_RATE: { + const int uid = IPCThreadState::self()->getCallingUid(); + if (uid == AID_ROOT || uid == AID_SYSTEM) { + return OK; + } + return PERMISSION_DENIED; + } case ON_PULL_ATOM: { const int uid = IPCThreadState::self()->getCallingUid(); if (uid == AID_SYSTEM) { @@ -5431,6 +5638,29 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return PERMISSION_DENIED; } + case CREATE_DISPLAY: + case DESTROY_DISPLAY: + case GET_PRIMARY_PHYSICAL_DISPLAY_ID: + case GET_PHYSICAL_DISPLAY_IDS: + case GET_PHYSICAL_DISPLAY_TOKEN: + case SET_POWER_MODE: + case GET_DISPLAY_STATE: + case GET_DISPLAY_STATS: + case CLEAR_BOOT_DISPLAY_MODE: + case GET_BOOT_DISPLAY_MODE_SUPPORT: + case SET_AUTO_LOW_LATENCY_MODE: + case SET_GAME_CONTENT_TYPE: + case CAPTURE_LAYERS: + case CAPTURE_DISPLAY: + case CAPTURE_DISPLAY_BY_ID: + case IS_WIDE_COLOR_DISPLAY: + case GET_DISPLAY_BRIGHTNESS_SUPPORT: + case SET_DISPLAY_BRIGHTNESS: + case ADD_HDR_LAYER_INFO_LISTENER: + case REMOVE_HDR_LAYER_INFO_LISTENER: + case NOTIFY_POWER_BOOST: + LOG_FATAL("Deprecated opcode: %d, migrated to AIDL", code); + return PERMISSION_DENIED; } // These codes are used for the IBinder protocol to either interrogate the recipient @@ -5441,9 +5671,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { code == IBinder::SYSPROPS_TRANSACTION) { return OK; } - // Numbers from 1000 to 1040 are currently used for backdoors. The code + // Numbers from 1000 to 1042 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1040) { + if (code >= 1000 && code <= 1042) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -5454,9 +5684,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - status_t credentialCheck = CheckTransactCodeCredentials(code); - if (credentialCheck != OK) { - return credentialCheck; + if (const status_t error = CheckTransactCodeCredentials(code); error != OK) { + return error; } status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); @@ -5473,47 +5702,41 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } int n; switch (code) { - case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE - case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE - return NO_ERROR; - case 1002: // SHOW_UPDATES - n = data.readInt32(); - mDebugRegion = n ? n : (mDebugRegion ? 0 : 1); - invalidateHwcGeometry(); - repaintEverything(); - return NO_ERROR; - case 1004:{ // repaint everything - repaintEverything(); + case 1000: // Unused. + case 1001: + return NAME_NOT_FOUND; + case 1002: // Toggle flashing on surface damage. + if (const int delay = data.readInt32(); delay > 0) { + mDebugFlashDelay = delay; + } else { + mDebugFlashDelay = mDebugFlashDelay ? 0 : 1; + } + scheduleRepaint(); return NO_ERROR; - } - case 1005:{ // force transaction - Mutex::Autolock _l(mStateLock); - setTransactionFlags( - eTransactionNeeded| - eDisplayTransactionNeeded| - eTraversalNeeded); + case 1004: // Force composite ahead of next VSYNC. + case 1006: + scheduleComposite(FrameHint::kActive); return NO_ERROR; - } - case 1006:{ // send empty update - signalRefresh(); + case 1005: { // Force commit ahead of next VSYNC. + Mutex::Autolock lock(mStateLock); + setTransactionFlags(eTransactionNeeded | eDisplayTransactionNeeded | + eTraversalNeeded); return NO_ERROR; } - case 1008: // toggle use of hw composer - n = data.readInt32(); - mDebugDisableHWC = n != 0; - invalidateHwcGeometry(); - repaintEverything(); + case 1007: // Unused. + return NAME_NOT_FOUND; + case 1008: // Toggle forced GPU composition. + mDebugDisableHWC = data.readInt32() != 0; + scheduleRepaint(); return NO_ERROR; - case 1009: // toggle use of transform hint - n = data.readInt32(); - mDebugDisableTransformHint = n != 0; - invalidateHwcGeometry(); - repaintEverything(); + case 1009: // Toggle use of transform hint. + mDebugDisableTransformHint = data.readInt32() != 0; + scheduleRepaint(); return NO_ERROR; - case 1010: // interrogate. + case 1010: // Interrogate. reply->writeInt32(0); reply->writeInt32(0); - reply->writeInt32(mDebugRegion); + reply->writeInt32(mDebugFlashDelay); reply->writeInt32(0); reply->writeInt32(mDebugDisableHWC); return NO_ERROR; @@ -5610,7 +5833,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } case 1021: { // Disable HWC virtual displays const bool enable = data.readInt32() != 0; - static_cast<void>(schedule([this, enable] { enableHalVirtualDisplays(enable); })); + static_cast<void>( + mScheduler->schedule([this, enable] { enableHalVirtualDisplays(enable); })); return NO_ERROR; } case 1022: { // Set saturation boost @@ -5627,8 +5851,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r if (data.readInt32(&colorMode) == NO_ERROR) { mForceColorMode = static_cast<ColorMode>(colorMode); } - invalidateHwcGeometry(); - repaintEverything(); + scheduleRepaint(); return NO_ERROR; } // Deprecate, use 1030 to check whether the device is color managed. @@ -5638,22 +5861,33 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r case 1025: { // Set layer tracing n = data.readInt32(); bool tracingEnabledChanged; - if (n) { + if (n == 1) { + int64_t fixedStartingTime = data.readInt64(); ALOGD("LayerTracing enabled"); - tracingEnabledChanged = mTracing.enable(); + tracingEnabledChanged = mLayerTracing.enable(); if (tracingEnabledChanged) { - schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait(); + int64_t startingTime = + (fixedStartingTime) ? fixedStartingTime : systemTime(); + mScheduler + ->schedule([&]() FTL_FAKE_GUARD(mStateLock) { + mLayerTracing.notify("start", startingTime); + }) + .wait(); } + } else if (n == 2) { + std::string filename = std::string(data.readCString()); + ALOGD("LayerTracing disabled. Trace wrote to %s", filename.c_str()); + tracingEnabledChanged = mLayerTracing.disable(filename.c_str()); } else { ALOGD("LayerTracing disabled"); - tracingEnabledChanged = mTracing.disable(); + tracingEnabledChanged = mLayerTracing.disable(); } mTracingEnabledChanged = tracingEnabledChanged; reply->writeInt32(NO_ERROR); return NO_ERROR; } case 1026: { // Get layer tracing status - reply->writeBool(mTracing.isEnabled()); + reply->writeBool(mLayerTracing.isEnabled()); return NO_ERROR; } // Is a DisplayColorSetting supported? @@ -5694,7 +5928,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } ALOGD("Updating trace buffer to %d KB", n); - mTracing.setBufferSize(n * 1024); + mLayerTracing.setBufferSize(n * 1024); reply->writeInt32(NO_ERROR); return NO_ERROR; } @@ -5739,79 +5973,95 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r case 1033: { n = data.readUint32(); ALOGD("Updating trace flags to 0x%x", n); - mTracing.setTraceFlags(n); + mLayerTracing.setTraceFlags(n); reply->writeInt32(NO_ERROR); return NO_ERROR; } case 1034: { - schedule([&] { + auto future = mScheduler->schedule([&] { switch (n = data.readInt32()) { case 0: case 1: - ON_MAIN_THREAD(enableRefreshRateOverlay(static_cast<bool>(n))); + FTL_FAKE_GUARD(mStateLock, + enableRefreshRateOverlay(static_cast<bool>(n))); break; default: { - reply->writeBool(ON_MAIN_THREAD(isRefreshRateOverlayEnabled())); + reply->writeBool( + FTL_FAKE_GUARD(mStateLock, isRefreshRateOverlayEnabled())); } } - }).get(); + }); + + future.wait(); return NO_ERROR; } case 1035: { const int modeId = data.readInt32(); - mDebugDisplayModeSetByBackdoor = false; - const auto displayId = [&]() -> std::optional<PhysicalDisplayId> { - uint64_t inputDisplayId = 0; - if (data.readUint64(&inputDisplayId) == NO_ERROR) { - const auto token = getPhysicalDisplayToken( - static_cast<PhysicalDisplayId>(inputDisplayId)); - if (!token) { - ALOGE("No display with id: %" PRIu64, inputDisplayId); - return std::nullopt; - } + const auto display = [&]() -> sp<IBinder> { + uint64_t value; + if (data.readUint64(&value) != NO_ERROR) { + return getDefaultDisplayDevice()->getDisplayToken().promote(); + } - return std::make_optional<PhysicalDisplayId>(inputDisplayId); + if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(value)) { + return getPhysicalDisplayToken(*id); } - return getDefaultDisplayDevice()->getPhysicalId(); + ALOGE("Invalid physical display ID"); + return nullptr; }(); - if (!displayId) { - ALOGE("No display found"); - return NO_ERROR; - } - - status_t result = setActiveMode(getPhysicalDisplayToken(*displayId), modeId); - if (result != NO_ERROR) { - return result; - } - - mDebugDisplayModeSetByBackdoor = true; - - return NO_ERROR; + mDebugDisplayModeSetByBackdoor = false; + const status_t result = setActiveModeFromBackdoor(display, modeId); + mDebugDisplayModeSetByBackdoor = result == NO_ERROR; + return result; } + // Turn on/off frame rate flexibility mode. When turned on it overrides the display + // manager frame rate policy a new policy which allows switching between all refresh + // rates. case 1036: { - if (data.readInt32() > 0) { - status_t result = - acquireFrameRateFlexibilityToken(&mDebugFrameRateFlexibilityToken); - if (result != NO_ERROR) { - return result; - } - } else { - mDebugFrameRateFlexibilityToken = nullptr; + if (data.readInt32() > 0) { // turn on + return mScheduler + ->schedule([this] { + const auto display = + FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); + + // This is a little racy, but not in a way that hurts anything. As + // we grab the defaultMode from the display manager policy, we could + // be setting a new display manager policy, leaving us using a stale + // defaultMode. The defaultMode doesn't matter for the override + // policy though, since we set allowGroupSwitching to true, so it's + // not a problem. + scheduler::RefreshRateConfigs::Policy overridePolicy; + overridePolicy.defaultMode = display->refreshRateConfigs() + .getDisplayManagerPolicy() + .defaultMode; + overridePolicy.allowGroupSwitching = true; + constexpr bool kOverridePolicy = true; + return setDesiredDisplayModeSpecsInternal(display, overridePolicy, + kOverridePolicy); + }) + .get(); + } else { // turn off + return mScheduler + ->schedule([this] { + const auto display = + FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); + constexpr bool kOverridePolicy = true; + return setDesiredDisplayModeSpecsInternal(display, {}, + kOverridePolicy); + }) + .get(); } - return NO_ERROR; } // Inject a hotplug connected event for the primary display. This will deallocate and // reallocate the display state including framebuffers. case 1037: { - std::optional<hal::HWDisplayId> hwcId; - { - Mutex::Autolock lock(mStateLock); - hwcId = getHwComposer().getInternalHwcDisplayId(); - } - onComposerHalHotplug(*hwcId, hal::Connection::CONNECTED); + const hal::HWDisplayId hwcId = + (Mutex::Autolock(mStateLock), getHwComposer().getPrimaryHwcDisplayId()); + + onComposerHalHotplug(hwcId, hal::Connection::CONNECTED); return NO_ERROR; } // Modify the max number of display frames stored within FrameTimeline @@ -5846,38 +6096,58 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r // Second argument is an optional uint64 - if present, then limits enabling/disabling // caching to a particular physical display case 1040: { - status_t error = - schedule([&] { - n = data.readInt32(); - std::optional<PhysicalDisplayId> inputId = std::nullopt; - if (uint64_t inputDisplayId; - data.readUint64(&inputDisplayId) == NO_ERROR) { - const auto token = getPhysicalDisplayToken( - static_cast<PhysicalDisplayId>(inputDisplayId)); - if (!token) { - ALOGE("No display with id: %" PRIu64, inputDisplayId); - return NAME_NOT_FOUND; - } - - inputId = std::make_optional<PhysicalDisplayId>(inputDisplayId); - } - { - Mutex::Autolock lock(mStateLock); - mLayerCachingEnabled = n != 0; - for (const auto& [_, display] : mDisplays) { - if (!inputId || *inputId == display->getPhysicalId()) { - display->enableLayerCaching(mLayerCachingEnabled); - } - } + auto future = mScheduler->schedule([&] { + n = data.readInt32(); + std::optional<PhysicalDisplayId> inputId = std::nullopt; + if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) { + inputId = DisplayId::fromValue<PhysicalDisplayId>(inputDisplayId); + if (!inputId || getPhysicalDisplayToken(*inputId)) { + ALOGE("No display with id: %" PRIu64, inputDisplayId); + return NAME_NOT_FOUND; + } + } + { + Mutex::Autolock lock(mStateLock); + mLayerCachingEnabled = n != 0; + for (const auto& [_, display] : mDisplays) { + if (!inputId || *inputId == display->getPhysicalId()) { + display->enableLayerCaching(mLayerCachingEnabled); } - return OK; - }).get(); + } + } + return OK; + }); - if (error != OK) { + if (const status_t error = future.get(); error != OK) { return error; } - invalidateHwcGeometry(); - repaintEverything(); + scheduleRepaint(); + return NO_ERROR; + } + case 1041: { // Transaction tracing + if (mTransactionTracing) { + if (data.readInt32()) { + // Transaction tracing is always running but allow the user to temporarily + // increase the buffer when actively debugging. + mTransactionTracing->setBufferSize( + TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE); + } else { + mTransactionTracing->writeToFile(); + mTransactionTracing->setBufferSize( + TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE); + } + } + reply->writeInt32(NO_ERROR); + return NO_ERROR; + } + case 1042: { // Write layers trace or transaction trace to file + if (mTransactionTracing) { + mTransactionTracing->writeToFile(); + } + if (mLayerTracingEnabled) { + mLayerTracing.writeToFile(); + } + reply->writeInt32(NO_ERROR); return NO_ERROR; } } @@ -5885,31 +6155,20 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return err; } -void SurfaceFlinger::repaintEverything() { - mRepaintEverything = true; - signalTransaction(); -} - -void SurfaceFlinger::repaintEverythingForHWC() { - mRepaintEverything = true; - mPowerAdvisor.notifyDisplayUpdateImminent(); - mEventQueue->invalidate(); -} - void SurfaceFlinger::kernelTimerChanged(bool expired) { static bool updateOverlay = property_get_bool("debug.sf.kernel_idle_timer_update_overlay", true); if (!updateOverlay) return; - if (Mutex::Autolock lock(mStateLock); !isRefreshRateOverlayEnabled()) return; // Update the overlay on the main thread to avoid race conditions with - // mRefreshRateConfigs->getCurrentRefreshRate() - static_cast<void>(schedule([=] { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + // mRefreshRateConfigs->getActiveMode() + static_cast<void>(mScheduler->schedule([=] { + const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); if (!display) { ALOGW("%s: default display is null", __func__); return; } + if (!display->isRefreshRateOverlayEnabled()) return; const auto desiredActiveMode = display->getDesiredActiveMode(); const std::optional<DisplayModeId> desiredModeId = desiredActiveMode @@ -5919,11 +6178,52 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { const bool timerExpired = mKernelIdleTimerEnabled && expired; if (display->onKernelTimerChanged(desiredModeId, timerExpired)) { - mEventQueue->invalidate(); + mScheduler->scheduleFrame(); } })); } +std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds> +SurfaceFlinger::getKernelIdleTimerProperties(DisplayId displayId) { + const bool isKernelIdleTimerHwcSupported = getHwComposer().getComposer()->isSupported( + android::Hwc2::Composer::OptionalFeature::KernelIdleTimer); + const auto timeout = getIdleTimerTimeout(displayId); + if (isKernelIdleTimerHwcSupported) { + if (const auto id = PhysicalDisplayId::tryCast(displayId); + getHwComposer().hasDisplayIdleTimerCapability(*id)) { + // In order to decide if we can use the HWC api for idle timer + // we query DisplayCapability::DISPLAY_IDLE_TIMER directly on the composer + // without relying on hasDisplayCapability. + // hasDisplayCapability relies on DisplayCapabilities + // which are updated after we set the PowerMode::ON. + // DISPLAY_IDLE_TIMER is a display driver property + // and is available before the PowerMode::ON + return {KernelIdleTimerController::HwcApi, timeout}; + } + return {std::nullopt, timeout}; + } + if (getKernelIdleTimerSyspropConfig(displayId)) { + return {KernelIdleTimerController::Sysprop, timeout}; + } + + return {std::nullopt, timeout}; +} + +void SurfaceFlinger::updateKernelIdleTimer(std::chrono::milliseconds timeout, + KernelIdleTimerController controller, + PhysicalDisplayId displayId) { + switch (controller) { + case KernelIdleTimerController::HwcApi: { + getHwComposer().setIdleTimerEnabled(displayId, timeout); + break; + } + case KernelIdleTimerController::Sysprop: { + base::SetProperty(KERNEL_IDLE_TIMER_PROP, timeout > 0ms ? "true" : "false"); + break; + } + } +} + void SurfaceFlinger::toggleKernelIdleTimer() { using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction; @@ -5935,23 +6235,31 @@ void SurfaceFlinger::toggleKernelIdleTimer() { // If the support for kernel idle timer is disabled for the active display, // don't do anything. - if (!display->refreshRateConfigs().supportsKernelIdleTimer()) { + const std::optional<KernelIdleTimerController> kernelIdleTimerController = + display->refreshRateConfigs().kernelIdleTimerController(); + if (!kernelIdleTimerController.has_value()) { return; } const KernelIdleTimerAction action = display->refreshRateConfigs().getIdleTimerAction(); + switch (action) { case KernelIdleTimerAction::TurnOff: if (mKernelIdleTimerEnabled) { ATRACE_INT("KernelIdleTimer", 0); - base::SetProperty(KERNEL_IDLE_TIMER_PROP, "false"); + std::chrono::milliseconds constexpr kTimerDisabledTimeout = 0ms; + updateKernelIdleTimer(kTimerDisabledTimeout, kernelIdleTimerController.value(), + display->getPhysicalId()); mKernelIdleTimerEnabled = false; } break; case KernelIdleTimerAction::TurnOn: if (!mKernelIdleTimerEnabled) { ATRACE_INT("KernelIdleTimer", 1); - base::SetProperty(KERNEL_IDLE_TIMER_PROP, "true"); + const std::chrono::milliseconds timeout = + display->refreshRateConfigs().getIdleTimerTimeout(); + updateKernelIdleTimer(timeout, kernelIdleTimerController.value(), + display->getPhysicalId()); mKernelIdleTimerEnabled = true; } break; @@ -6114,12 +6422,13 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, traverseLayersInLayerStack(layerStack, args.uid, visitor); }; - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, args.allowProtected, args.grayscale, - captureListener); + auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, args.allowProtected, args.grayscale, + captureListener); + return fenceStatus(future.get()); } -status_t SurfaceFlinger::captureDisplay(uint64_t displayIdOrLayerStack, +status_t SurfaceFlinger::captureDisplay(DisplayId displayId, const sp<IScreenCaptureListener>& captureListener) { ui::LayerStack layerStack; wp<const DisplayDevice> displayWeak; @@ -6127,21 +6436,14 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayIdOrLayerStack, ui::Dataspace dataspace; { Mutex::Autolock lock(mStateLock); - auto display = getDisplayDeviceLocked(PhysicalDisplayId{displayIdOrLayerStack}); - - // Fall back to first display whose layer stack matches. - if (!display) { - const auto layerStack = static_cast<ui::LayerStack>(displayIdOrLayerStack); - display = findDisplay(WithLayerStack(layerStack)); - } + const auto display = getDisplayDeviceLocked(displayId); if (!display) { return NAME_NOT_FOUND; } - layerStack = display->getLayerStack(); displayWeak = display; - + layerStack = display->getLayerStack(); size = display->getLayerStackSpaceRect().getSize(); dataspace = @@ -6158,9 +6460,18 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayIdOrLayerStack, traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor); }; - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, - ui::PixelFormat::RGBA_8888, false /* allowProtected */, - false /* grayscale */, captureListener); + if (captureListener == nullptr) { + ALOGE("capture screen must provide a capture listener callback"); + return BAD_VALUE; + } + + constexpr bool kAllowProtected = false; + constexpr bool kGrayscale = false; + + auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, + ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale, + captureListener); + return fenceStatus(future.get()); } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -6175,7 +6486,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, ui::Size reqSize; sp<Layer> parent; Rect crop(args.sourceCrop); - std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers; + std::unordered_set<sp<Layer>, SpHash<Layer>> excludeLayers; ui::Dataspace dataspace; // Call this before holding mStateLock to avoid any deadlocking. @@ -6229,17 +6540,6 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, // and failed if display is not in native mode. This provide a way to force using native // colors when capture. dataspace = args.dataspace; - if (dataspace == ui::Dataspace::UNKNOWN) { - auto display = findDisplay(WithLayerStack(parent->getLayerStack())); - if (!display) { - // If the layer is not on a display, use the dataspace for the default display. - display = getDefaultDisplayDeviceLocked(); - } - - const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode; - dataspace = pickDataspaceFromColorMode(colorMode); - } - } // mStateLock // really small crop or frameScale @@ -6278,23 +6578,28 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, }); }; - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, args.allowProtected, args.grayscale, - captureListener); + if (captureListener == nullptr) { + ALOGE("capture screen must provide a capture listener callback"); + return BAD_VALUE; + } + + auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, args.allowProtected, args.grayscale, + captureListener); + return fenceStatus(future.get()); } -status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, - TraverseLayersFunction traverseLayers, - ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - bool allowProtected, bool grayscale, - const sp<IScreenCaptureListener>& captureListener) { +ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon( + RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, + ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale, + const sp<IScreenCaptureListener>& captureListener) { ATRACE_CALL(); if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) { ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32 ") that exceeds render target size limit.", bufferSize.getWidth(), bufferSize.getHeight()); - return BAD_VALUE; + return ftl::yield<FenceResult>(base::unexpected(BAD_VALUE)).share(); } // Loop over all visible layers to see whether there's any protected layer. A protected layer is @@ -6304,14 +6609,15 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, const bool supportsProtected = getRenderEngine().supportsProtectedContent(); bool hasProtectedLayer = false; if (allowProtected && supportsProtected) { - hasProtectedLayer = schedule([=]() { - bool protectedLayerFound = false; - traverseLayers([&](Layer* layer) { - protectedLayerFound = protectedLayerFound || - (layer->isVisible() && layer->isProtected()); - }); - return protectedLayerFound; - }).get(); + auto future = mScheduler->schedule([=]() { + bool protectedLayerFound = false; + traverseLayers([&](Layer* layer) { + protectedLayerFound = + protectedLayerFound || (layer->isVisible() && layer->isProtected()); + }); + return protectedLayerFound; + }); + hasProtectedLayer = future.get(); } const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | @@ -6327,57 +6633,68 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d", bufferStatus); - const auto texture = std::make_shared< - renderengine::ExternalTexture>(buffer, getRenderEngine(), - renderengine::ExternalTexture::Usage::WRITEABLE); + const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared< + renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), + renderengine::impl::ExternalTexture::Usage:: + WRITEABLE); return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, texture, false /* regionSampling */, grayscale, captureListener); } -status_t SurfaceFlinger::captureScreenCommon( +ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon( RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, const sp<IScreenCaptureListener>& captureListener) { ATRACE_CALL(); - if (captureListener == nullptr) { - ALOGE("capture screen must provide a capture listener callback"); - return BAD_VALUE; - } - bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); - static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable { - if (mRefreshPending) { - ALOGW("Skipping screenshot for now"); - captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling, - grayscale, captureListener); - return; - } + auto future = mScheduler->schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable + -> ftl::SharedFuture<FenceResult> { ScreenCaptureResults captureResults; std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get(); if (!renderArea) { ALOGW("Skipping screen capture because of invalid render area."); captureResults.result = NO_MEMORY; captureListener->onScreenCaptureCompleted(captureResults); - return; + return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); } - status_t result = NO_ERROR; + ftl::SharedFuture<FenceResult> renderFuture; renderArea->render([&] { - result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, - canCaptureBlackoutContent, regionSampling, grayscale, - captureResults); + renderFuture = + renderScreenImpl(*renderArea, traverseLayers, buffer, canCaptureBlackoutContent, + regionSampling, grayscale, captureResults); }); - captureResults.result = result; - captureListener->onScreenCaptureCompleted(captureResults); - })); + if (captureListener) { + // TODO: The future returned by std::async blocks the main thread. Return a chain of + // futures to the Binder thread instead. + std::async([=]() mutable { + ATRACE_NAME("captureListener is nonnull!"); + auto fenceResult = renderFuture.get(); + // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult. + captureResults.result = fenceStatus(fenceResult); + captureResults.fence = std::move(fenceResult).value_or(Fence::NO_FENCE); + captureListener->onScreenCaptureCompleted(captureResults); + }); + } + return renderFuture; + }); - return NO_ERROR; + if (captureListener) { + return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); + } + + // Flatten nested futures. + auto chain = ftl::Future(std::move(future)).then([](ftl::SharedFuture<FenceResult> future) { + return future; + }); + + return chain.share(); } -status_t SurfaceFlinger::renderScreenImplLocked( +ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( const RenderArea& renderArea, TraverseLayersFunction traverseLayers, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool canCaptureBlackoutContent, bool regionSampling, bool grayscale, @@ -6389,18 +6706,40 @@ status_t SurfaceFlinger::renderScreenImplLocked( captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure()); }); - const bool useProtected = buffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED; + const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED; // We allow the system server to take screenshots of secure layers for // use in situations like the Screen-rotation animation and place // the impetus on WindowManager to not persist them. if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) { ALOGW("FB is protected: PERMISSION_DENIED"); - return PERMISSION_DENIED; + return ftl::yield<FenceResult>(base::unexpected(PERMISSION_DENIED)).share(); } captureResults.buffer = buffer->getBuffer(); - captureResults.capturedDataspace = renderArea.getReqDataSpace(); + auto dataspace = renderArea.getReqDataSpace(); + auto parent = renderArea.getParentLayer(); + auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC; + auto sdrWhitePointNits = DisplayDevice::sDefaultMaxLumiance; + auto displayBrightnessNits = DisplayDevice::sDefaultMaxLumiance; + + if ((dataspace == ui::Dataspace::UNKNOWN) && (parent != nullptr)) { + Mutex::Autolock lock(mStateLock); + auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) { + return display.getLayerStack() == layerStack; + }); + if (!display) { + // If the layer is not on a display, use the dataspace for the default display. + display = getDefaultDisplayDeviceLocked(); + } + + const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode; + dataspace = pickDataspaceFromColorMode(colorMode); + renderIntent = display->getCompositionDisplay()->getState().renderIntent; + sdrWhitePointNits = display->getCompositionDisplay()->getState().sdrWhitePointNits; + displayBrightnessNits = display->getCompositionDisplay()->getState().displayBrightnessNits; + } + captureResults.capturedDataspace = dataspace; const auto reqWidth = renderArea.getReqWidth(); const auto reqHeight = renderArea.getReqHeight(); @@ -6418,8 +6757,11 @@ status_t SurfaceFlinger::renderScreenImplLocked( clientCompositionDisplay.clip = sourceCrop; clientCompositionDisplay.orientation = rotation; - clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace(); + clientCompositionDisplay.outputDataspace = dataspace; + clientCompositionDisplay.currentLuminanceNits = displayBrightnessNits; clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance; + clientCompositionDisplay.renderIntent = + static_cast<aidl::android::hardware::graphics::composer3::RenderIntent>(renderIntent); const float colorSaturation = grayscale ? 0 : 1; clientCompositionDisplay.colorTransform = calculateColorMatrix(colorSaturation); @@ -6436,7 +6778,6 @@ status_t SurfaceFlinger::renderScreenImplLocked( const auto display = renderArea.getDisplayDevice(); std::vector<Layer*> renderedLayers; - Region clearRegion = Region::INVALID_REGION; bool disableBlurs = false; traverseLayers([&](Layer* layer) { disableBlurs |= layer->getDrawingState().sidebandStream != nullptr; @@ -6448,7 +6789,6 @@ status_t SurfaceFlinger::renderScreenImplLocked( renderArea.needsFiltering(), renderArea.isSecure(), useProtected, - clearRegion, layerStackSpaceRect, clientCompositionDisplay.outputDataspace, true, /* realContentIsVisible */ @@ -6457,6 +6797,8 @@ status_t SurfaceFlinger::renderScreenImplLocked( BlurSetting::Disabled : compositionengine::LayerFE::ClientCompositionTargetSettings:: BlurSetting::Enabled, + isHdrLayer(layer) ? displayBrightnessNits : sdrWhitePointNits, + }; std::vector<compositionengine::LayerFE::LayerSettings> results = layer->prepareClientCompositionList(targetSettings); @@ -6470,6 +6812,7 @@ status_t SurfaceFlinger::renderScreenImplLocked( if (regionSampling) { settings.backgroundBlurRadius = 0; } + captureResults.capturedHdrLayers |= isHdrLayer(layer); } clientCompositionLayers.insert(clientCompositionLayers.end(), @@ -6480,35 +6823,34 @@ status_t SurfaceFlinger::renderScreenImplLocked( }); - std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers( - clientCompositionLayers.size()); + std::vector<renderengine::LayerSettings> clientRenderEngineLayers; + clientRenderEngineLayers.reserve(clientCompositionLayers.size()); std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(), - clientCompositionLayerPointers.begin(), - std::pointer_traits<renderengine::LayerSettings*>::pointer_to); + std::back_inserter(clientRenderEngineLayers), + [](compositionengine::LayerFE::LayerSettings& settings) + -> renderengine::LayerSettings { return settings; }); - clientCompositionDisplay.clearRegion = clearRegion; // Use an empty fence for the buffer fence, since we just created the buffer so // there is no need for synchronization with the GPU. base::unique_fd bufferFence; - base::unique_fd drawFence; getRenderEngine().useProtectedContext(useProtected); - const constexpr bool kUseFramebufferCache = false; - getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, - kUseFramebufferCache, std::move(bufferFence), &drawFence); + constexpr bool kUseFramebufferCache = false; + auto chain = + ftl::Future(getRenderEngine().drawLayers(clientCompositionDisplay, + clientRenderEngineLayers, buffer, + kUseFramebufferCache, std::move(bufferFence))) + .then(&toFenceResult); - if (drawFence >= 0) { - sp<Fence> releaseFence = new Fence(dup(drawFence)); - for (auto* layer : renderedLayers) { - layer->onLayerDisplayed(releaseFence); - } + const auto future = chain.share(); + for (auto* layer : renderedLayers) { + layer->onLayerDisplayed(future); } - captureResults.fence = new Fence(drawFence.release()); // Always switch back to unprotected context. getRenderEngine().useProtectedContext(false); - return NO_ERROR; + return future; } void SurfaceFlinger::windowInfosReported() { @@ -6535,12 +6877,12 @@ void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const // We loop through the first level of layers without traversing, // as we need to determine which layers belong to the requested display. for (const auto& layer : mDrawingState.layersSortedByZ) { - if (!layer->belongsToDisplay(layerStack)) { + if (layer->getLayerStack() != layerStack) { continue; } // relative layers are traversed in Layer::traverseInZOrder layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - if (layer->getPrimaryDisplayOnly()) { + if (layer->isInternalDisplayOverlay()) { return; } if (!layer->isVisible()) { @@ -6604,7 +6946,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) { ALOGV("switching to Scheduler preferred display mode %d", preferredDisplayMode->getId().value()); - setDesiredActiveMode({preferredDisplayMode, Scheduler::ModeEvent::Changed}); + setDesiredActiveMode({preferredDisplayMode, DisplayModeEvent::Changed}); } else { LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", preferredDisplayMode->getId().value()); @@ -6623,8 +6965,8 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecs( return BAD_VALUE; } - auto future = schedule([=]() -> status_t { - const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken)); + auto future = mScheduler->schedule([=]() -> status_t { + const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken)); if (!display) { ALOGE("Attempt to set desired display modes for invalid display token %p", displayToken.get()); @@ -6636,8 +6978,10 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecs( using Policy = scheduler::RefreshRateConfigs::Policy; const Policy policy{DisplayModeId(defaultMode), allowGroupSwitching, - {Fps(primaryRefreshRateMin), Fps(primaryRefreshRateMax)}, - {Fps(appRequestRefreshRateMin), Fps(appRequestRefreshRateMax)}}; + {Fps::fromValue(primaryRefreshRateMin), + Fps::fromValue(primaryRefreshRateMax)}, + {Fps::fromValue(appRequestRefreshRateMin), + Fps::fromValue(appRequestRefreshRateMax)}}; constexpr bool kOverridePolicy = false; return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy); @@ -6699,6 +7043,13 @@ void SurfaceFlinger::onLayerDestroyed(Layer* layer) { if (!layer->isRemovedFromCurrentState()) { mScheduler->deregisterLayer(layer); } + if (mTransactionTracing) { + mTransactionTracing->onLayerRemoved(layer->getSequence()); + } +} + +void SurfaceFlinger::onLayerUpdate() { + scheduleCommit(FrameHint::kActive); } // WARNING: ONLY CALL THIS FROM LAYER DTOR @@ -6754,7 +7105,7 @@ status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, return BAD_VALUE; } - static_cast<void>(schedule([=] { + static_cast<void>(mScheduler->schedule([=] { Mutex::Autolock lock(mStateLock); if (authenticateSurfaceTextureLocked(surface)) { sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer(); @@ -6765,7 +7116,7 @@ status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, const auto strategy = Layer::FrameRate::convertChangeFrameRateStrategy(changeFrameRateStrategy); if (layer->setFrameRate( - Layer::FrameRate(Fps{frameRate}, + Layer::FrameRate(Fps::fromValue(frameRate), Layer::FrameRate::convertCompatibility(compatibility), strategy))) { setTransactionFlags(eTraversalNeeded); @@ -6780,72 +7131,15 @@ status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, return NO_ERROR; } -status_t SurfaceFlinger::acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) { - if (!outToken) { - return BAD_VALUE; - } - - auto future = schedule([this] { - status_t result = NO_ERROR; - sp<IBinder> token; - - if (mFrameRateFlexibilityTokenCount == 0) { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - - // This is a little racy, but not in a way that hurts anything. As we grab the - // defaultMode from the display manager policy, we could be setting a new display - // manager policy, leaving us using a stale defaultMode. The defaultMode doesn't - // matter for the override policy though, since we set allowGroupSwitching to - // true, so it's not a problem. - scheduler::RefreshRateConfigs::Policy overridePolicy; - overridePolicy.defaultMode = - display->refreshRateConfigs().getDisplayManagerPolicy().defaultMode; - overridePolicy.allowGroupSwitching = true; - constexpr bool kOverridePolicy = true; - result = setDesiredDisplayModeSpecsInternal(display, overridePolicy, kOverridePolicy); - } - - if (result == NO_ERROR) { - mFrameRateFlexibilityTokenCount++; - // Handing out a reference to the SurfaceFlinger object, as we're doing in the line - // below, is something to consider carefully. The lifetime of the - // FrameRateFlexibilityToken isn't tied to SurfaceFlinger object lifetime, so if this - // SurfaceFlinger object were to be destroyed while the token still exists, the token - // destructor would be accessing a stale SurfaceFlinger reference, and crash. This is ok - // in this case, for two reasons: - // 1. Once SurfaceFlinger::run() is called by main_surfaceflinger.cpp, the only way - // the program exits is via a crash. So we won't have a situation where the - // SurfaceFlinger object is dead but the process is still up. - // 2. The frame rate flexibility token is acquired/released only by CTS tests, so even - // if condition 1 were changed, the problem would only show up when running CTS tests, - // not on end user devices, so we could spot it and fix it without serious impact. - token = new FrameRateFlexibilityToken( - [this]() { onFrameRateFlexibilityTokenReleased(); }); - ALOGD("Frame rate flexibility token acquired. count=%d", - mFrameRateFlexibilityTokenCount); - } - - return std::make_pair(result, token); - }); - - status_t result; - std::tie(result, *outToken) = future.get(); - return result; -} +status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { + PhysicalDisplayId displayId = [&]() { + Mutex::Autolock lock(mStateLock); + return getDefaultDisplayDeviceLocked()->getPhysicalId(); + }(); -void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() { - static_cast<void>(schedule([this] { - LOG_ALWAYS_FATAL_IF(mFrameRateFlexibilityTokenCount == 0, - "Failed tracking frame rate flexibility tokens"); - mFrameRateFlexibilityTokenCount--; - ALOGD("Frame rate flexibility token released. count=%d", mFrameRateFlexibilityTokenCount); - if (mFrameRateFlexibilityTokenCount == 0) { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - constexpr bool kOverridePolicy = true; - status_t result = setDesiredDisplayModeSpecsInternal(display, {}, kOverridePolicy); - LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token"); - } - })); + mScheduler->setGameModeRefreshRateForUid(FrameRateOverride{static_cast<uid_t>(uid), frameRate}); + mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId); + return NO_ERROR; } status_t SurfaceFlinger::setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, @@ -6899,33 +7193,29 @@ int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, } status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { - const auto maxSupportedRefreshRate = [&] { - const auto display = getDefaultDisplayDevice(); - if (display) { - return display->refreshRateConfigs().getSupportedRefreshRateRange().max; + Fps maxRefreshRate = 60_Hz; + + if (!getHwComposer().isHeadless()) { + if (const auto display = getDefaultDisplayDevice()) { + maxRefreshRate = display->refreshRateConfigs().getSupportedRefreshRateRange().max; } - ALOGW("%s: default display is null", __func__); - return Fps(60); - }(); - *buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate); + } + + *buffers = getMaxAcquiredBufferCountForRefreshRate(maxRefreshRate); return NO_ERROR; } -int SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const { - const auto refreshRate = [&] { - const auto frameRateOverride = mScheduler->getFrameRateOverride(uid); - if (frameRateOverride.has_value()) { - return frameRateOverride.value(); - } +uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const { + Fps refreshRate = 60_Hz; - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - if (display) { - return display->refreshRateConfigs().getCurrentRefreshRate().getFps(); + if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) { + refreshRate = *frameRateOverride; + } else if (!getHwComposer().isHeadless()) { + if (const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked())) { + refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); } + } - ALOGW("%s: default display is null", __func__); - return Fps(60); - }(); return getMaxAcquiredBufferCountForRefreshRate(refreshRate); } @@ -6935,71 +7225,24 @@ int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) con return calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } -void SurfaceFlinger::TransactionState::traverseStatesWithBuffers( - std::function<void(const layer_state_t&)> visitor) { - for (const auto& state : states) { - if (state.state.hasBufferChanges() && state.state.hasValidBuffer() && state.state.surface) { - visitor(state.state); - } - } -} - -void SurfaceFlinger::setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer, - const wp<IBinder>& parent, const wp<Layer> parentLayer, - const wp<IBinder>& producer, bool addToRoot) { - Mutex::Autolock lock(mCreatedLayersLock); - mCreatedLayers[handle->localBinder()] = - std::make_unique<LayerCreatedState>(layer, parent, parentLayer, producer, addToRoot); -} - -auto SurfaceFlinger::getLayerCreatedState(const sp<IBinder>& handle) { - Mutex::Autolock lock(mCreatedLayersLock); - BBinder* b = nullptr; - if (handle) { - b = handle->localBinder(); - } - - if (b == nullptr) { - return std::unique_ptr<LayerCreatedState>(nullptr); - } - - auto it = mCreatedLayers.find(b); - if (it == mCreatedLayers.end()) { - ALOGE("Can't find layer from handle %p", handle.get()); - return std::unique_ptr<LayerCreatedState>(nullptr); - } - - auto state = std::move(it->second); - mCreatedLayers.erase(it); - return state; -} - -sp<Layer> SurfaceFlinger::handleLayerCreatedLocked(const sp<IBinder>& handle) { - const auto& state = getLayerCreatedState(handle); - if (!state) { - return nullptr; - } - - sp<Layer> layer = state->layer.promote(); +void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) { + sp<Layer> layer = state.layer.promote(); if (!layer) { - ALOGE("Invalid layer %p", state->layer.unsafe_get()); - return nullptr; + ALOGD("Layer was destroyed soon after creation %p", state.layer.unsafe_get()); + return; } sp<Layer> parent; - bool allowAddRoot = state->addToRoot; - if (state->initialParent != nullptr) { - parent = fromHandle(state->initialParent.promote()).promote(); + bool addToRoot = state.addToRoot; + if (state.initialParent != nullptr) { + parent = state.initialParent.promote(); if (parent == nullptr) { - ALOGE("Invalid parent %p", state->initialParent.unsafe_get()); - allowAddRoot = false; + ALOGD("Parent was destroyed soon after creation %p", state.initialParent.unsafe_get()); + addToRoot = false; } - } else if (state->initialParentLayer != nullptr) { - parent = state->initialParentLayer.promote(); - allowAddRoot = false; } - if (parent == nullptr && allowAddRoot) { + if (parent == nullptr && addToRoot) { layer->setIsAtRoot(true); mCurrentState.layersSortedByZ.add(layer); } else if (parent == nullptr) { @@ -7013,32 +7256,15 @@ sp<Layer> SurfaceFlinger::handleLayerCreatedLocked(const sp<IBinder>& handle) { layer->updateTransformHint(mActiveDisplayTransformHint); - if (state->initialProducer != nullptr) { - mGraphicBufferProducerList.insert(state->initialProducer); - LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > mMaxGraphicBufferProducerListSize, - "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", - mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize, - mNumLayers.load()); - if (mGraphicBufferProducerList.size() > mGraphicBufferProducerListSizeLogThreshold) { - ALOGW("Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", - mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize, - mNumLayers.load()); - } - } - - return layer; -} - -void SurfaceFlinger::scheduleRegionSamplingThread() { - static_cast<void>(schedule([&] { notifyRegionSamplingThread(); })); + mInterceptor->saveSurfaceCreation(layer); } -void SurfaceFlinger::notifyRegionSamplingThread() { +void SurfaceFlinger::sample() { if (!mLumaSampling || !mRegionSamplingThread) { return; } - mRegionSamplingThread->onCompositionComplete(mEventQueue->nextExpectedInvalidate()); + mRegionSamplingThread->onCompositionComplete(mScheduler->getScheduledFrameTime()); } void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay) { @@ -7082,6 +7308,270 @@ status_t SurfaceFlinger::removeWindowInfosListener( return NO_ERROR; } +std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextureFromBufferData( + const BufferData& bufferData, const char* layerName) const { + bool cacheIdChanged = bufferData.flags.test(BufferData::BufferDataChange::cachedBufferChanged); + bool bufferSizeExceedsLimit = false; + std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr; + if (cacheIdChanged && bufferData.buffer != nullptr) { + bufferSizeExceedsLimit = exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(), + bufferData.buffer->getHeight()); + if (!bufferSizeExceedsLimit) { + ClientCache::getInstance().add(bufferData.cachedBuffer, bufferData.buffer); + buffer = ClientCache::getInstance().get(bufferData.cachedBuffer); + } + } else if (cacheIdChanged) { + buffer = ClientCache::getInstance().get(bufferData.cachedBuffer); + } else if (bufferData.buffer != nullptr) { + bufferSizeExceedsLimit = exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(), + bufferData.buffer->getHeight()); + if (!bufferSizeExceedsLimit) { + buffer = std::make_shared< + renderengine::impl::ExternalTexture>(bufferData.buffer, getRenderEngine(), + renderengine::impl::ExternalTexture:: + Usage::READABLE); + } + } + ALOGE_IF(bufferSizeExceedsLimit, + "Attempted to create an ExternalTexture for layer %s that exceeds render target size " + "limit.", + layerName); + return buffer; +} + +bool SurfaceFlinger::commitCreatedLayers() { + std::vector<LayerCreatedState> createdLayers; + { + std::scoped_lock<std::mutex> lock(mCreatedLayersLock); + createdLayers = std::move(mCreatedLayers); + mCreatedLayers.clear(); + if (createdLayers.size() == 0) { + return false; + } + } + + Mutex::Autolock _l(mStateLock); + for (const auto& createdLayer : createdLayers) { + handleLayerCreatedLocked(createdLayer); + } + createdLayers.clear(); + mLayersAdded = true; + return true; +} + +// gui::ISurfaceComposer + +binder::Status SurfaceComposerAIDL::createDisplay(const std::string& displayName, bool secure, + sp<IBinder>* outDisplay) { + status_t status = checkAccessPermission(); + if (status == OK) { + String8 displayName8 = String8::format("%s", displayName.c_str()); + *outDisplay = mFlinger->createDisplay(displayName8, secure); + return binder::Status::ok(); + } + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::destroyDisplay(const sp<IBinder>& display) { + status_t status = checkAccessPermission(); + if (status == OK) { + mFlinger->destroyDisplay(display); + return binder::Status::ok(); + } + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) { + std::vector<PhysicalDisplayId> physicalDisplayIds = mFlinger->getPhysicalDisplayIds(); + std::vector<int64_t> displayIds; + displayIds.reserve(physicalDisplayIds.size()); + for (auto item : physicalDisplayIds) { + displayIds.push_back(static_cast<int64_t>(item.value)); + } + *outDisplayIds = displayIds; + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binder::Status::fromStatusT(status); + } + + PhysicalDisplayId id; + status = mFlinger->getPrimaryPhysicalDisplayId(&id); + if (status == NO_ERROR) { + *outDisplayId = id.value; + } + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId, + sp<IBinder>* outDisplay) { + const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId)); + *outDisplay = mFlinger->getPhysicalDisplayToken(*id); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::setPowerMode(const sp<IBinder>& display, int mode) { + status_t status = checkAccessPermission(); + if (status != OK) return binder::Status::fromStatusT(status); + + mFlinger->setPowerMode(display, mode); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display, + gui::DisplayStatInfo* outStatInfo) { + DisplayStatInfo statInfo; + status_t status = mFlinger->getDisplayStats(display, &statInfo); + if (status == NO_ERROR) { + outStatInfo->vsyncTime = static_cast<long>(statInfo.vsyncTime); + outStatInfo->vsyncPeriod = static_cast<long>(statInfo.vsyncPeriod); + } + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display, + gui::DisplayState* outState) { + ui::DisplayState state; + status_t status = mFlinger->getDisplayState(display, &state); + if (status == NO_ERROR) { + outState->layerStack = state.layerStack.id; + outState->orientation = static_cast<gui::Rotation>(state.orientation); + outState->layerStackSpaceRect.width = state.layerStackSpaceRect.width; + outState->layerStackSpaceRect.height = state.layerStackSpaceRect.height; + } + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) { + status_t status = checkAccessPermission(); + if (status != OK) return binder::Status::fromStatusT(status); + + status = mFlinger->clearBootDisplayMode(display); + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getBootDisplayModeSupport(bool* outMode) { + status_t status = checkAccessPermission(); + if (status != OK) return binder::Status::fromStatusT(status); + + status = mFlinger->getBootDisplayModeSupport(outMode); + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) { + status_t status = checkAccessPermission(); + if (status != OK) return binder::Status::fromStatusT(status); + + mFlinger->setAutoLowLatencyMode(display, on); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& display, bool on) { + status_t status = checkAccessPermission(); + if (status != OK) return binder::Status::fromStatusT(status); + + mFlinger->setGameContentType(display, on); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::captureDisplay( + const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { + status_t status = mFlinger->captureDisplay(args, captureListener); + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::captureDisplayById( + int64_t displayId, const sp<IScreenCaptureListener>& captureListener) { + status_t status; + IPCThreadState* ipc = IPCThreadState::self(); + const int uid = ipc->getCallingUid(); + if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { + std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId)); + status = mFlinger->captureDisplay(*id, captureListener); + } else { + status = PERMISSION_DENIED; + } + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::captureLayers( + const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { + status_t status = mFlinger->captureLayers(args, captureListener); + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::isWideColorDisplay(const sp<IBinder>& token, + bool* outIsWideColorDisplay) { + status_t status = mFlinger->isWideColorDisplay(token, outIsWideColorDisplay); + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDisplayBrightnessSupport(const sp<IBinder>& displayToken, + bool* outSupport) { + status_t status = mFlinger->getDisplayBrightnessSupport(displayToken, outSupport); + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setDisplayBrightness(const sp<IBinder>& displayToken, + const gui::DisplayBrightness& brightness) { + status_t status = checkControlDisplayBrightnessPermission(); + if (status != OK) return binder::Status::fromStatusT(status); + + status = mFlinger->setDisplayBrightness(displayToken, brightness); + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addHdrLayerInfoListener( + const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) { + status_t status = checkControlDisplayBrightnessPermission(); + if (status != OK) return binder::Status::fromStatusT(status); + + status = mFlinger->addHdrLayerInfoListener(displayToken, listener); + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener( + const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) { + status_t status = checkControlDisplayBrightnessPermission(); + if (status != OK) return binder::Status::fromStatusT(status); + + status = mFlinger->removeHdrLayerInfoListener(displayToken, listener); + return binder::Status::fromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) { + status_t status = checkAccessPermission(); + if (status != OK) return binder::Status::fromStatusT(status); + + status = mFlinger->notifyPowerBoost(boostId); + return binder::Status::fromStatusT(status); +} + +status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) { + if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { + IPCThreadState* ipc = IPCThreadState::self(); + ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", ipc->getCallingPid(), + ipc->getCallingUid()); + return PERMISSION_DENIED; + } + return OK; +} + +status_t SurfaceComposerAIDL::checkControlDisplayBrightnessPermission() { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) { + ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + return OK; +} + } // namespace android #if defined(__gl_h_) |