diff options
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 4007 |
1 files changed, 2401 insertions, 1606 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4698ac6199..230810c936 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -28,8 +29,10 @@ #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/types.h> -#include <android/hardware/power/1.0/IPower.h> +#include <android/hardware/power/Boost.h> #include <android/native_window.h> +#include <android/os/BnSetInputWindowsListener.h> +#include <android/os/IInputFlinger.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/PermissionCache.h> @@ -42,52 +45,53 @@ #include <compositionengine/OutputLayer.h> #include <compositionengine/RenderSurface.h> #include <compositionengine/impl/OutputCompositionState.h> +#include <compositionengine/impl/OutputLayerCompositionState.h> #include <configstore/Utils.h> #include <cutils/compiler.h> #include <cutils/properties.h> -#include <dlfcn.h> -#include <errno.h> +#include <ftl/future.h> #include <gui/BufferQueue.h> #include <gui/DebugEGLImageTracker.h> -#include <gui/GuiConfig.h> #include <gui/IDisplayEventConnection.h> #include <gui/IProducerListener.h> #include <gui/LayerDebugInfo.h> #include <gui/LayerMetadata.h> #include <gui/LayerState.h> #include <gui/Surface.h> +#include <gui/TraceUtils.h> #include <hidl/ServiceManagement.h> -#include <input/IInputFlinger.h> #include <layerproto/LayerProtoParser.h> #include <log/log.h> #include <private/android_filesystem_config.h> #include <private/gui/SyncFeatures.h> +#include <processgroup/processgroup.h> #include <renderengine/RenderEngine.h> -#include <statslog.h> #include <sys/types.h> #include <ui/ColorSpace.h> #include <ui/DebugUtils.h> -#include <ui/DisplayConfig.h> -#include <ui/DisplayInfo.h> +#include <ui/DisplayId.h> +#include <ui/DisplayMode.h> #include <ui/DisplayStatInfo.h> #include <ui/DisplayState.h> +#include <ui/DynamicDisplayInfo.h> #include <ui/GraphicBufferAllocator.h> #include <ui/PixelFormat.h> -#include <ui/UiConfig.h> +#include <ui/StaticDisplayInfo.h> #include <utils/StopWatch.h> #include <utils/String16.h> #include <utils/String8.h> #include <utils/Timers.h> -#include <utils/Trace.h> #include <utils/misc.h> #include <algorithm> +#include <cerrno> #include <cinttypes> #include <cmath> #include <cstdint> #include <functional> #include <mutex> #include <optional> +#include <type_traits> #include <unordered_map> #include "BufferLayer.h" @@ -101,31 +105,37 @@ #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" +#include "DisplayHardware/Hal.h" #include "DisplayHardware/VirtualDisplaySurface.h" +#include "DisplayRenderArea.h" #include "EffectLayer.h" #include "Effects/Daltonizer.h" +#include "FpsReporter.h" +#include "FrameTimeline/FrameTimeline.h" #include "FrameTracer/FrameTracer.h" +#include "HdrLayerInfoReporter.h" #include "Layer.h" +#include "LayerRenderArea.h" #include "LayerVector.h" #include "MonitoredProducer.h" #include "NativeWindowSurface.h" -#include "Promise.h" #include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" -#include "Scheduler/DispSync.h" #include "Scheduler/DispSyncSource.h" -#include "Scheduler/EventControlThread.h" #include "Scheduler/EventThread.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/MessageQueue.h" -#include "Scheduler/PhaseOffsets.h" #include "Scheduler/Scheduler.h" +#include "Scheduler/VsyncConfiguration.h" +#include "Scheduler/VsyncController.h" #include "StartPropertySetThread.h" #include "SurfaceFlingerProperties.h" #include "SurfaceInterceptor.h" #include "TimeStats/TimeStats.h" +#include "TunnelModeEnabledReporter.h" #include "android-base/parseint.h" #include "android-base/stringprintf.h" +#include "android-base/strings.h" #define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock) @@ -148,12 +158,11 @@ using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; using namespace android::sysprop; -using android::hardware::power::V1_0::PowerHint; +using android::hardware::power::Boost; using base::StringAppendF; using ui::ColorMode; using ui::Dataspace; using ui::DisplayPrimaries; -using ui::Hdr; using ui::RenderIntent; namespace hal = android::hardware::graphics::composer::hal; @@ -224,7 +233,7 @@ struct SCOPED_CAPABILITY UnnecessaryLock { ~UnnecessaryLock() RELEASE() {} }; -// TODO(b/141333600): Consolidate with HWC2::Display::Config::Builder::getDefaultDensity. +// TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity. constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV; float getDensityFromProperty(const char* property, bool required) { @@ -251,20 +260,43 @@ private: std::function<void()> mCallback; }; +enum Permission { + ACCESS_SURFACE_FLINGER = 0x1, + ROTATE_SURFACE_FLINGER = 0x2, +}; + } // namespace anonymous +struct SetInputWindowsListener : os::BnSetInputWindowsListener { + explicit SetInputWindowsListener(std::function<void()> listenerCb) : mListenerCb(listenerCb) {} + + binder::Status onSetInputWindowsFinished() override; + + std::function<void()> mListenerCb; +}; + +binder::Status SetInputWindowsListener::onSetInputWindowsFinished() { + if (mListenerCb != nullptr) { + mListenerCb(); + } + return binder::Status::ok(); +} + // --------------------------------------------------------------------------- const String16 sHardwareTest("android.permission.HARDWARE_TEST"); const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); +const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER"); 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 char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled"; // --------------------------------------------------------------------------- int64_t SurfaceFlinger::dispSyncPresentTimeOffset; bool SurfaceFlinger::useHwcForRgbToYuv; -uint64_t SurfaceFlinger::maxVirtualDisplaySize; bool SurfaceFlinger::hasSyncFramework; int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; uint32_t SurfaceFlinger::maxGraphicsWidth; @@ -278,20 +310,8 @@ ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat: Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; bool SurfaceFlinger::useFrameRateApi; - -std::string getHwcServiceName() { - char value[PROPERTY_VALUE_MAX] = {}; - property_get("debug.sf.hwc_service_name", value, "default"); - ALOGI("Using HWComposer service: '%s'", value); - return std::string(value); -} - -bool useTrebleTestingOverride() { - char value[PROPERTY_VALUE_MAX] = {}; - property_get("debug.sf.treble_testing_override", value, "false"); - ALOGI("Treble testing override: '%s'", value); - return std::string(value) == "true"; -} +bool SurfaceFlinger::enableSdrDimming; +bool SurfaceFlinger::enableLatchUnsignaled; std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { switch(displayColorSetting) { @@ -307,17 +327,31 @@ std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { } } -SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {} +bool callingThreadHasRotateSurfaceFlingerAccess() { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + return uid == AID_GRAPHICS || uid == AID_SYSTEM || + PermissionCache::checkPermission(sRotateSurfaceFlinger, pid, uid); +} SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) : mFactory(factory), - mInterceptor(mFactory.createSurfaceInterceptor(this)), + mInterceptor(mFactory.createSurfaceInterceptor()), mTimeStats(std::make_shared<impl::TimeStats>()), - mFrameTracer(std::make_unique<FrameTracer>()), + mFrameTracer(mFactory.createFrameTracer()), + mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())), mEventQueue(mFactory.createMessageQueue()), 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)) {} + mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)), + mPowerAdvisor(*this) { + ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); + + mSetInputWindowsListener = new SetInputWindowsListener([&]() { setInputWindowsFinished(); }); +} SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) { ALOGI("SurfaceFlinger is starting"); @@ -328,8 +362,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false); - maxVirtualDisplaySize = max_virtual_display_dimension(0); - maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2); maxGraphicsWidth = std::max(max_graphics_width(0), 0); @@ -337,7 +369,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI hasWideColorDisplay = has_wide_color_display(false); - useColorManagement = use_color_management(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)); @@ -353,6 +387,12 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mColorSpaceAgnosticDataspace = static_cast<ui::Dataspace>(color_space_agnostic_dataspace(Dataspace::UNKNOWN)); + mLayerCachingEnabled = [] { + const bool enable = + android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false); + return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable); + }(); + useContextPriority = use_context_priority(true); using Values = SurfaceFlingerProperties::primary_display_orientation_values; @@ -392,23 +432,11 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI int debugDdms = atoi(value); ALOGI_IF(debugDdms, "DDMS debugging not supported"); - property_get("debug.sf.disable_backpressure", value, "0"); - mPropagateBackpressure = !atoi(value); - ALOGI_IF(!mPropagateBackpressure, "Disabling backpressure propagation"); - property_get("debug.sf.enable_gl_backpressure", value, "0"); mPropagateBackpressureClientComposition = atoi(value); ALOGI_IF(mPropagateBackpressureClientComposition, "Enabling backpressure propagation for Client Composition"); - property_get("debug.sf.enable_hwc_vds", value, "0"); - mUseHwcVirtualDisplays = atoi(value); - ALOGI_IF(mUseHwcVirtualDisplays, "Enabling HWC virtual displays"); - - property_get("ro.sf.disable_triple_buffer", value, "0"); - mLayerTripleBufferingDisabled = atoi(value); - ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering"); - property_get("ro.surface_flinger.supports_background_blur", value, "0"); bool supportsBlurs = atoi(value); mSupportsBlur = supportsBlurs; @@ -419,6 +447,10 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI const size_t defaultListSize = ISurfaceComposer::MAX_LAYERS; auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize)); mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize; + mGraphicBufferProducerListSizeLogThreshold = + std::max(static_cast<int>(0.95 * + static_cast<double>(mMaxGraphicBufferProducerListSize)), + 1); property_get("debug.sf.luma_sampling", value, "1"); mLumaSampling = atoi(value); @@ -431,12 +463,13 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI // comes online to attempt to read the property. The property is // instead read after the boot animation - if (useTrebleTestingOverride()) { + if (base::GetBoolProperty("debug.sf.treble_testing_override"s, false)) { // Without the override SurfaceFlinger cannot connect to HIDL // services that are not listed in the manifests. Considered // deriving the setting from the set service name, but it // would be brittle if the name that's not 'default' is used // for production purposes later on. + ALOGI("Enabling Treble testing override"); android::hardware::details::setTrebleTestingOverride(true); } @@ -444,6 +477,13 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mKernelIdleTimerEnabled = mSupportKernelIdleTimer = sysprop::support_kernel_idle_timer(false); base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false"); + + 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)); + + enableLatchUnsignaled = base::GetBoolProperty("debug.sf.latch_unsignaled"s, false); } SurfaceFlinger::~SurfaceFlinger() = default; @@ -456,6 +496,9 @@ 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; })); + // restore initial conditions (default device unblank, etc) initializeDisplays(); @@ -482,6 +525,15 @@ sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() { } sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secure) { + // onTransact already checks for some permissions, but adding an additional check here. + // This is to ensure that only system and graphics can request to create a secure + // display. Secure displays can show secure content so we add an additional restriction on it. + const int uid = IPCThreadState::self()->getCallingUid(); + if (secure && uid != AID_GRAPHICS && uid != AID_SYSTEM) { + ALOGE("Only privileged processes can create a secure display"); + return nullptr; + } + class DisplayToken : public BBinder { sp<SurfaceFlinger> flinger; virtual ~DisplayToken() { @@ -527,6 +579,59 @@ void SurfaceFlinger::destroyDisplay(const sp<IBinder>& displayToken) { setTransactionFlags(eDisplayTransactionNeeded); } +void SurfaceFlinger::enableHalVirtualDisplays(bool enable) { + auto& generator = mVirtualDisplayIdGenerators.hal; + if (!generator && enable) { + ALOGI("Enabling HAL virtual displays"); + generator.emplace(getHwComposer().getMaxVirtualDisplayCount()); + } else if (generator && !enable) { + ALOGW_IF(generator->inUse(), "Disabling HAL virtual displays while in use"); + generator.reset(); + } +} + +VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, ui::PixelFormat format, + ui::LayerStack layerStack) { + if (auto& generator = mVirtualDisplayIdGenerators.hal) { + if (const auto id = generator->generateId()) { + std::optional<PhysicalDisplayId> mirror; + + if (const auto display = findDisplay([layerStack](const auto& display) { + return !display.isVirtual() && display.getLayerStack() == layerStack; + })) { + mirror = display->getPhysicalId(); + } + + if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format, mirror)) { + return *id; + } + + generator->releaseId(*id); + } else { + ALOGW("%s: Exhausted HAL virtual displays", __func__); + } + + ALOGW("%s: Falling back to GPU virtual display", __func__); + } + + const auto id = mVirtualDisplayIdGenerators.gpu.generateId(); + LOG_ALWAYS_FATAL_IF(!id, "Failed to generate ID for GPU virtual display"); + return *id; +} + +void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { + if (const auto id = HalVirtualDisplayId::tryCast(displayId)) { + if (auto& generator = mVirtualDisplayIdGenerators.hal) { + generator->releaseId(*id); + } + return; + } + + const auto id = GpuVirtualDisplayId::tryCast(displayId); + LOG_ALWAYS_FATAL_IF(!id); + mVirtualDisplayIdGenerators.gpu.releaseId(*id); +} + std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const { Mutex::Autolock lock(mStateLock); @@ -537,11 +642,11 @@ std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const { std::vector<PhysicalDisplayId> displayIds; displayIds.reserve(mPhysicalDisplayTokens.size()); - displayIds.push_back(internalDisplayId->value); + displayIds.push_back(*internalDisplayId); for (const auto& [id, token] : mPhysicalDisplayTokens) { if (id != *internalDisplayId) { - displayIds.push_back(id.value); + displayIds.push_back(id); } } @@ -550,7 +655,7 @@ std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const { sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const { Mutex::Autolock lock(mStateLock); - return getPhysicalDisplayTokenLocked(DisplayId{displayId}); + return getPhysicalDisplayTokenLocked(displayId); } status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const { @@ -573,8 +678,7 @@ compositionengine::CompositionEngine& SurfaceFlinger::getCompositionEngine() con return *mCompositionEngine.get(); } -void SurfaceFlinger::bootFinished() -{ +void SurfaceFlinger::bootFinished() { if (mBootFinished == true) { ALOGE("Extra call to bootFinished"); return; @@ -583,12 +687,16 @@ void SurfaceFlinger::bootFinished() if (mStartPropertySetThread->join() != NO_ERROR) { ALOGE("Join StartPropertySetThread failed!"); } + + if (mRenderEnginePrimeCacheFuture.valid()) { + mRenderEnginePrimeCacheFuture.get(); + } const nsecs_t now = systemTime(); const nsecs_t duration = now - mBootTime; ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); mFrameTracer->initialize(); - mTimeStats->onBootFinished(); + mFrameTimeline->onBootFinished(); // wait patiently for the window manager death const String16 name("window"); @@ -612,7 +720,7 @@ void SurfaceFlinger::bootFinished() if (input == nullptr) { ALOGE("Failed to link to input service"); } else { - mInputFlinger = interface_cast<IInputFlinger>(input); + mInputFlinger = interface_cast<os::IInputFlinger>(input); } readPersistentProperties(); @@ -641,12 +749,16 @@ uint32_t SurfaceFlinger::getNewTexture() { // The pool was empty, so we need to get a new texture name directly using a // blocking call to the main thread - return schedule([this] { + auto genTextures = [this] { uint32_t name = 0; getRenderEngine().genTextures(1, &name); return name; - }) - .get(); + }; + if (std::this_thread::get_id() == mMainThreadId) { + return genTextures(); + } else { + return schedule(genTextures).get(); + } } void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { @@ -669,24 +781,38 @@ void SurfaceFlinger::init() { // 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::HIGH - : renderengine::RenderEngine::ContextPriority::MEDIUM) - .build())); + .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())); + + // Set SF main policy after initializing RenderEngine which has its own policy. + if (!SetTaskProfiles(0, {"SFMainPolicy"})) { + ALOGW("Failed to set main task profile"); + } + mCompositionEngine->setTimeStats(mTimeStats); - mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName)); - mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId); + mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName)); + mCompositionEngine->getHwComposer().setCallback(this); + ClientCache::getInstance().setRenderEngine(&getRenderEngine()); + + if (base::GetBoolProperty("debug.sf.enable_hwc_vds"s, false)) { + enableHalVirtualDisplays(true); + } + // 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(!getHwComposer().isConnected(*display->getId()), + const auto displayId = display->getPhysicalId(); + LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId), "Internal display is disconnected."); // initialize our drawing state @@ -695,12 +821,24 @@ void SurfaceFlinger::init() { // set initial conditions (e.g. unblank default device) initializeDisplays(); + mPowerAdvisor.init(); + char primeShaderCache[PROPERTY_VALUE_MAX]; property_get("service.sf.prime_shader_cache", primeShaderCache, "1"); if (atoi(primeShaderCache)) { - getRenderEngine().primeCache(); + if (setSchedFifo(false) != NO_ERROR) { + ALOGW("Can't set SCHED_OTHER for primeCache"); + } + + mRenderEnginePrimeCacheFuture = getRenderEngine().primeCache(); + + if (setSchedFifo(true) != NO_ERROR) { + ALOGW("Can't set SCHED_OTHER for primeCache"); + } } + getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize()); + // Inform native graphics APIs whether the present timestamp is supported: const bool presentFenceReliable = @@ -729,11 +867,6 @@ void SurfaceFlinger::readPersistentProperties() { property_get("persist.sys.sf.color_mode", value, "0"); mForceColorMode = static_cast<ColorMode>(atoi(value)); - - property_get("persist.sys.sf.disable_blurs", value, "0"); - bool disableBlurs = atoi(value); - mDisableBlurs = disableBlurs; - ALOGI_IF(disableBlurs, "Disabling blur effects, user preference."); } void SurfaceFlinger::startBootAnim() { @@ -803,13 +936,15 @@ status_t SurfaceFlinger::getDisplayState(const sp<IBinder>& displayToken, ui::Di state->layerStack = display->getLayerStack(); state->orientation = display->getOrientation(); - const Rect viewport = display->getViewport(); - state->viewport = viewport.isValid() ? viewport.getSize() : display->getSize(); + const Rect layerStackRect = display->getLayerStackSpaceRect(); + state->layerStackSpaceRect = + layerStackRect.isValid() ? layerStackRect.getSize() : display->getSize(); return NO_ERROR; } -status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& displayToken, DisplayInfo* info) { +status_t SurfaceFlinger::getStaticDisplayInfo(const sp<IBinder>& displayToken, + ui::StaticDisplayInfo* info) { if (!displayToken || !info) { return BAD_VALUE; } @@ -830,68 +965,71 @@ status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& displayToken, Display if (mEmulatedDisplayDensity) { info->density = mEmulatedDisplayDensity; } else { - info->density = info->connectionType == DisplayConnectionType::Internal + info->density = info->connectionType == ui::DisplayConnectionType::Internal ? mInternalDisplayDensity : FALLBACK_DENSITY; } info->density /= ACONFIGURATION_DENSITY_MEDIUM; info->secure = display->isSecure(); - info->deviceProductInfo = getDeviceProductInfoLocked(*display); + info->deviceProductInfo = display->getDeviceProductInfo(); return NO_ERROR; } -status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken, - Vector<DisplayConfig>* configs) { - if (!displayToken || !configs) { +status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, + ui::DynamicDisplayInfo* info) { + if (!displayToken || !info) { return BAD_VALUE; } Mutex::Autolock lock(mStateLock); - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { return NAME_NOT_FOUND; } - const bool isInternal = (displayId == getInternalDisplayIdLocked()); - - configs->clear(); + info->activeDisplayModeId = static_cast<int32_t>(display->getActiveMode()->getId().value()); - for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) { - DisplayConfig config; + 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 = hwConfig->getWidth(); - auto height = hwConfig->getHeight(); + auto width = mode->getWidth(); + auto height = mode->getHeight(); - auto xDpi = hwConfig->getDpiX(); - auto yDpi = hwConfig->getDpiY(); + auto xDpi = mode->getDpiX(); + auto yDpi = mode->getDpiY(); - if (isInternal && + if (display->isPrimary() && (internalDisplayOrientation == ui::ROTATION_90 || internalDisplayOrientation == ui::ROTATION_270)) { std::swap(width, height); std::swap(xDpi, yDpi); } - config.resolution = ui::Size(width, height); + outMode.resolution = ui::Size(width, height); if (mEmulatedDisplayDensity) { - config.xDpi = mEmulatedDisplayDensity; - config.yDpi = mEmulatedDisplayDensity; + outMode.xDpi = mEmulatedDisplayDensity; + outMode.yDpi = mEmulatedDisplayDensity; } else { - config.xDpi = xDpi; - config.yDpi = yDpi; + outMode.xDpi = xDpi; + outMode.yDpi = yDpi; } - const nsecs_t period = hwConfig->getVsyncPeriod(); - config.refreshRate = 1e9f / period; + const nsecs_t period = mode->getVsyncPeriod(); + outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue(); - const auto offsets = mPhaseConfiguration->getOffsetsForRefreshRate(config.refreshRate); - config.appVsyncOffset = offsets.late.app; - config.sfVsyncOffset = offsets.late.sf; - config.configGroup = hwConfig->getConfigGroup(); + const auto vsyncConfigSet = + mVsyncConfiguration->getConfigsForRefreshRate(Fps(outMode.refreshRate)); + outMode.appVsyncOffset = vsyncConfigSet.late.appOffset; + outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset; + outMode.group = mode->getGroup(); // This is how far in advance a buffer must be queued for // presentation at a given time. If you want a buffer to appear @@ -900,16 +1038,29 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken, // // Normally it's one full refresh period (to give SF a chance to // latch the buffer), but this can be reduced by configuring a - // DispSync offset. Any additional delays introduced by the hardware + // VsyncController offset. Any additional delays introduced by the hardware // composer or panel must be accounted for here. // // We add an additional 1ms to allow for processing time and // differences between the ideal and actual refresh rate. - config.presentationDeadline = period - config.sfVsyncOffset + 1000000; + outMode.presentationDeadline = period - outMode.sfVsyncOffset + 1000000; - configs->push_back(config); + info->supportedDisplayModes.push_back(outMode); } + info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; + const auto displayId = display->getPhysicalId(); + info->supportedColorModes = getDisplayColorModes(displayId); + + 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; + }); return NO_ERROR; } @@ -918,57 +1069,31 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* st return BAD_VALUE; } - mScheduler->getDisplayStatInfo(stats); + *stats = mScheduler->getDisplayStatInfo(systemTime()); return NO_ERROR; } -int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) { - int activeConfig; - bool isPrimary; - - { - Mutex::Autolock lock(mStateLock); - - if (const auto display = getDisplayDeviceLocked(displayToken)) { - activeConfig = display->getActiveConfig().value(); - isPrimary = display->isPrimary(); - } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); - return NAME_NOT_FOUND; - } - } - - if (isPrimary) { - if (const auto config = getDesiredActiveConfig()) { - return config->configId.value(); - } - } - - return activeConfig; -} - -void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { +void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { ATRACE_CALL(); - auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId); - ALOGV("setDesiredActiveConfig(%s)", refreshRate.getName().c_str()); - - std::lock_guard<std::mutex> lock(mActiveConfigLock); - if (mDesiredActiveConfigChanged) { - // If a config change is pending, just cache the latest request in - // mDesiredActiveConfig - const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event; - mDesiredActiveConfig = info; - mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig; + auto refreshRate = mRefreshRateConfigs->getRefreshRateFromModeId(info.modeId); + ALOGV("%s(%s)", __func__, refreshRate.getName().c_str()); + + std::lock_guard<std::mutex> lock(mActiveModeLock); + if (mDesiredActiveModeChanged) { + // If a mode change is pending, just cache the latest request in mDesiredActiveMode + const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event; + mDesiredActiveMode = info; + mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig; } else { - // Check is we are already at the desired config + // Check if we are already at the desired mode const auto display = getDefaultDisplayDeviceLocked(); - if (!display || display->getActiveConfig() == refreshRate.getConfigId()) { + if (!display || display->getActiveMode()->getId() == refreshRate.getModeId()) { return; } - // Initiate a config change. - mDesiredActiveConfigChanged = true; - mDesiredActiveConfig = info; + // Initiate a mode change. + mDesiredActiveModeChanged = true; + mDesiredActiveMode = info; // This will trigger HWC refresh without resetting the idle timer. repaintEverythingForHWC(); @@ -976,20 +1101,15 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { // switch. mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod()); // As we called to set period, we will call to onRefreshRateChangeCompleted once - // DispSync model is locked. - mVSyncModulator->onRefreshRateChangeInitiated(); + // VsyncController model is locked. + modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated); - mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps()); - mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets()); - mScheduler->setConfigChangePending(true); - } - - if (mRefreshRateOverlay) { - mRefreshRateOverlay->changeRefreshRate(refreshRate); + updatePhaseConfiguration(refreshRate.getFps()); + mScheduler->setModeChangePending(true); } } -status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) { +status_t SurfaceFlinger::setActiveMode(const sp<IBinder>& displayToken, int modeId) { ATRACE_CALL(); if (!displayToken) { @@ -999,26 +1119,38 @@ status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mo auto future = schedule([=]() -> status_t { const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken)); if (!display) { - ALOGE("Attempt to set allowed display configs for invalid display token %p", + ALOGE("Attempt to set allowed display modes for invalid display token %p", displayToken.get()); return NAME_NOT_FOUND; - } else if (display->isVirtual()) { - ALOGW("Attempt to set allowed display configs for virtual display"); + } + + if (display->isVirtual()) { + ALOGW("Attempt to set allowed display modes for virtual display"); return INVALID_OPERATION; - } else { - const HwcConfigIndexType config(mode); - const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps(); - const scheduler::RefreshRateConfigs::Policy policy{config, {fps, fps}}; - constexpr bool kOverridePolicy = false; + } - return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy); + const auto mode = display->getMode(DisplayModeId{modeId}); + if (!mode) { + ALOGW("Attempt to switch to an unsupported mode %d.", modeId); + return BAD_VALUE; } + + const auto fps = mode->getFps(); + // Keep the old switching type. + const auto allowGroupSwitching = + mRefreshRateConfigs->getCurrentPolicy().allowGroupSwitching; + const scheduler::RefreshRateConfigs::Policy policy{mode->getId(), + allowGroupSwitching, + {fps, fps}}; + constexpr bool kOverridePolicy = false; + + return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy); }); return future.get(); } -void SurfaceFlinger::setActiveConfigInternal() { +void SurfaceFlinger::setActiveModeInternal() { ATRACE_CALL(); const auto display = getDefaultDisplayDeviceLocked(); @@ -1026,80 +1158,107 @@ void SurfaceFlinger::setActiveConfigInternal() { return; } - auto& oldRefreshRate = - mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig()); + const auto upcomingMode = display->getMode(mUpcomingActiveMode.modeId); + if (!upcomingMode) { + ALOGW("Upcoming active mode is no longer supported. Mode ID = %d", + mUpcomingActiveMode.modeId.value()); + // TODO(b/159590486) Handle the error better. Some parts of SurfaceFlinger may + // have been already updated with the upcoming active mode. + return; + } - std::lock_guard<std::mutex> lock(mActiveConfigLock); - mRefreshRateConfigs->setCurrentConfigId(mUpcomingActiveConfig.configId); - mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId); - display->setActiveConfig(mUpcomingActiveConfig.configId); + if (display->getActiveMode()->getSize() != upcomingMode->getSize()) { + auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken()); + // We need to generate new sequenceId in order to recreate the display (and this + // way the framebuffer). + state.sequenceId = DisplayDeviceState{}.sequenceId; + state.physical->activeMode = upcomingMode; + processDisplayChangesLocked(); - auto& refreshRate = - mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId); - if (refreshRate.getVsyncPeriod() != oldRefreshRate.getVsyncPeriod()) { - mTimeStats->incrementRefreshRateSwitches(); + // processDisplayChangesLocked will update all necessary components so we're done here. + return; } - mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps()); - mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets()); - ATRACE_INT("ActiveConfigFPS", refreshRate.getFps()); - if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) { - const nsecs_t vsyncPeriod = - mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId) - .getVsyncPeriod(); - mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, display->getId()->value, - mUpcomingActiveConfig.configId, vsyncPeriod); + std::lock_guard<std::mutex> lock(mActiveModeLock); + mRefreshRateConfigs->setCurrentModeId(mUpcomingActiveMode.modeId); + display->setActiveMode(mUpcomingActiveMode.modeId); + + const Fps refreshRate = upcomingMode->getFps(); + + mRefreshRateStats->setRefreshRate(refreshRate); + + updatePhaseConfiguration(refreshRate); + ATRACE_INT("ActiveConfigFPS", refreshRate.getValue()); + + if (mRefreshRateOverlay) { + mRefreshRateOverlay->changeRefreshRate(upcomingMode->getFps()); } + + if (mUpcomingActiveMode.event != Scheduler::ModeEvent::None) { + const nsecs_t vsyncPeriod = refreshRate.getPeriodNsecs(); + const auto physicalId = display->getPhysicalId(); + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId, + mUpcomingActiveMode.modeId, vsyncPeriod); + } +} + +void SurfaceFlinger::clearDesiredActiveModeState() { + std::lock_guard<std::mutex> lock(mActiveModeLock); + mDesiredActiveMode.event = Scheduler::ModeEvent::None; + mDesiredActiveModeChanged = false; + mScheduler->setModeChangePending(false); } -void SurfaceFlinger::desiredActiveConfigChangeDone() { - std::lock_guard<std::mutex> lock(mActiveConfigLock); - mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; - mDesiredActiveConfigChanged = false; +void SurfaceFlinger::desiredActiveModeChangeDone() { + const auto modeId = getDesiredActiveMode()->modeId; - const auto& refreshRate = - mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId); - mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod()); - mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps()); - mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets()); - mScheduler->setConfigChangePending(false); + clearDesiredActiveModeState(); + + const auto refreshRate = getDefaultDisplayDeviceLocked()->getMode(modeId)->getFps(); + mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs()); + updatePhaseConfiguration(refreshRate); } -void SurfaceFlinger::performSetActiveConfig() { +void SurfaceFlinger::performSetActiveMode() { ATRACE_CALL(); - ALOGV("performSetActiveConfig"); + ALOGV("%s", __FUNCTION__); // Store the local variable to release the lock. - const auto desiredActiveConfig = getDesiredActiveConfig(); - if (!desiredActiveConfig) { - // No desired active config pending to be applied + const auto desiredActiveMode = getDesiredActiveMode(); + if (!desiredActiveMode) { + // No desired active mode pending to be applied return; } - auto& refreshRate = - mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig->configId); - ALOGV("performSetActiveConfig changing active config to %d(%s)", - refreshRate.getConfigId().value(), refreshRate.getName().c_str()); const auto display = getDefaultDisplayDeviceLocked(); - if (!display || display->getActiveConfig() == desiredActiveConfig->configId) { + const auto desiredMode = display->getMode(desiredActiveMode->modeId); + if (!desiredMode) { + ALOGW("Desired display mode is no longer supported. Mode ID = %d", + desiredActiveMode->modeId.value()); + clearDesiredActiveModeState(); + return; + } + const auto refreshRate = desiredMode->getFps(); + ALOGV("%s changing active mode to %d(%s)", __FUNCTION__, desiredMode->getId().value(), + to_string(refreshRate).c_str()); + + if (!display || display->getActiveMode()->getId() == desiredActiveMode->modeId) { // display is not valid or we are already in the requested mode // on both cases there is nothing left to do - desiredActiveConfigChangeDone(); + desiredActiveModeChangeDone(); return; } - // Desired active config was set, it is different than the config currently in use, however - // allowed configs might have change by the time we process the refresh. - // Make sure the desired config is still allowed - if (!isDisplayConfigAllowed(desiredActiveConfig->configId)) { - desiredActiveConfigChangeDone(); + // Desired active mode was set, it is different than the mode currently in use, however + // allowed modes might have changed by the time we process the refresh. + // Make sure the desired mode is still allowed + if (!isDisplayModeAllowed(desiredActiveMode->modeId)) { + desiredActiveModeChangeDone(); return; } - mUpcomingActiveConfig = *desiredActiveConfig; - const auto displayId = display->getId(); - LOG_ALWAYS_FATAL_IF(!displayId); + mUpcomingActiveMode = *desiredActiveMode; - ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.getFps()); + ATRACE_INT("ActiveModeFPS_HWC", refreshRate.getValue()); // TODO(b/142753666) use constrains hal::VsyncPeriodChangeConstraints constraints; @@ -1107,55 +1266,48 @@ void SurfaceFlinger::performSetActiveConfig() { constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline outTimeline; - auto status = - getHwComposer().setActiveConfigWithConstraints(*displayId, - mUpcomingActiveConfig.configId.value(), - constraints, &outTimeline); + const auto status = + display->initiateModeChange(mUpcomingActiveMode.modeId, constraints, &outTimeline); if (status != NO_ERROR) { - // setActiveConfigWithConstraints may fail if a hotplug event is just about + // initiateModeChange may fail if a hotplug event is just about // to be sent. We just log the error in this case. - ALOGW("setActiveConfigWithConstraints failed: %d", status); + ALOGW("initiateModeChange failed: %d", status); return; } mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline); + // Scheduler will submit an empty frame to HWC if needed. - mSetActiveConfigPending = true; + mSetActiveModePending = true; } -status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken, - Vector<ColorMode>* outColorModes) { - if (!displayToken || !outColorModes) { - return BAD_VALUE; - } - - std::vector<ColorMode> modes; - bool isInternalDisplay = false; - { - ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); - - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - return NAME_NOT_FOUND; +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); + } } + }).wait(); +} - modes = getHwComposer().getColorModes(*displayId); - isInternalDisplay = displayId == getInternalDisplayIdLocked(); - } - outColorModes->clear(); +std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) { + auto modes = getHwComposer().getColorModes(displayId); + bool isInternalDisplay = displayId == getInternalDisplayIdLocked(); // If it's built-in display 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) { - std::remove_copy_if(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes), - isWideColorMode); - } else { - std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes)); + const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode); + modes.erase(newEnd, modes.end()); } - return NO_ERROR; + return modes; } status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken, @@ -1173,19 +1325,14 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayTok return NO_ERROR; } -ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) { - Mutex::Autolock lock(mStateLock); - - if (const auto display = getDisplayDeviceLocked(displayToken)) { - return display->getCompositionDisplay()->getState().colorMode; - } - return static_cast<ColorMode>(BAD_VALUE); -} - status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) { schedule([=]() MAIN_THREAD { - Vector<ColorMode> modes; - getDisplayColorModes(displayToken, &modes); + 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", @@ -1210,24 +1357,6 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, Col return NO_ERROR; } -status_t SurfaceFlinger::getAutoLowLatencyModeSupport(const sp<IBinder>& displayToken, - bool* outSupport) const { - if (!displayToken) { - return BAD_VALUE; - } - - Mutex::Autolock lock(mStateLock); - - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - return NAME_NOT_FOUND; - } - *outSupport = - getHwComposer().hasDisplayCapability(*displayId, - hal::DisplayCapability::AUTO_LOW_LATENCY_MODE); - return NO_ERROR; -} - void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) { static_cast<void>(schedule([=]() MAIN_THREAD { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { @@ -1238,27 +1367,6 @@ void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool })); } -status_t SurfaceFlinger::getGameContentTypeSupport(const sp<IBinder>& displayToken, - bool* outSupport) const { - if (!displayToken) { - return BAD_VALUE; - } - - Mutex::Autolock lock(mStateLock); - - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - return NAME_NOT_FOUND; - } - - std::vector<hal::ContentType> types; - getHwComposer().getSupportedContentTypes(*displayId, &types); - - *outSupport = std::any_of(types.begin(), types.end(), - [](auto type) { return type == hal::ContentType::GAME; }); - return NO_ERROR; -} - void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) { static_cast<void>(schedule([=]() MAIN_THREAD { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { @@ -1282,50 +1390,24 @@ status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const { return NO_ERROR; } -status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& displayToken, - HdrCapabilities* outCapabilities) const { +status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken, + const std::vector<ui::Hdr>& hdrTypes) { Mutex::Autolock lock(mStateLock); - const auto display = getDisplayDeviceLocked(displayToken); + auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); return NAME_NOT_FOUND; } - // At this point the DisplayDevice should already be set up, - // meaning the luminance information is already queried from - // hardware composer and stored properly. - const HdrCapabilities& capabilities = display->getHdrCapabilities(); - *outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(), - capabilities.getDesiredMaxLuminance(), - capabilities.getDesiredMaxAverageLuminance(), - capabilities.getDesiredMinLuminance()); - + display->overrideHdrTypes(hdrTypes); + dispatchDisplayHotplugEvent(display->getPhysicalId(), true /* connected */); return NO_ERROR; } -std::optional<DeviceProductInfo> SurfaceFlinger::getDeviceProductInfoLocked( - const DisplayDevice& display) const { - // TODO(b/149075047): Populate DeviceProductInfo on hotplug and store it in DisplayDevice to - // avoid repetitive HAL IPC and EDID parsing. - const auto displayId = display.getId(); - LOG_FATAL_IF(!displayId); - - const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId); - LOG_FATAL_IF(!hwcDisplayId); - - uint8_t port; - DisplayIdentificationData data; - if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) { - ALOGV("%s: No identification data.", __FUNCTION__); - return {}; - } - - const auto info = parseDisplayIdentificationData(port, data); - if (!info) { - return {}; - } - return info->deviceProductInfo; +status_t SurfaceFlinger::onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) { + *success = mTimeStats->onPullAtom(atomId, pulledData); + return NO_ERROR; } status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken, @@ -1406,8 +1488,7 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { Mutex::Autolock lock(mStateLock); if (const auto handle = mScheduler->enableVSyncInjection(enable)) { - mEventQueue->setEventConnection( - mScheduler->getEventConnection(enable ? handle : mSfConnectionHandle)); + mEventQueue->setInjector(enable ? mScheduler->getEventConnection(handle) : nullptr); } }).wait(); @@ -1416,7 +1497,12 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { status_t SurfaceFlinger::injectVSync(nsecs_t when) { Mutex::Autolock lock(mStateLock); - return mScheduler->injectVSync(when, calculateExpectedPresentTime(when)) ? NO_ERROR : BAD_VALUE; + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(when); + const auto expectedPresent = calculateExpectedPresentTime(stats); + return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent, + /*deadlineTimestamp=*/expectedPresent) + ? NO_ERROR + : BAD_VALUE; } status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) { @@ -1461,6 +1547,43 @@ status_t SurfaceFlinger::removeRegionSamplingListener(const sp<IRegionSamplingLi return NO_ERROR; } +status_t SurfaceFlinger::addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) { + if (!listener) { + return BAD_VALUE; + } + + mFpsReporter->addListener(listener, taskId); + return NO_ERROR; +} + +status_t SurfaceFlinger::removeFpsListener(const sp<gui::IFpsListener>& listener) { + if (!listener) { + return BAD_VALUE; + } + mFpsReporter->removeListener(listener); + return NO_ERROR; +} + +status_t SurfaceFlinger::addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + if (!listener) { + return BAD_VALUE; + } + + mTunnelModeEnabledReporter->addListener(listener); + return NO_ERROR; +} + +status_t SurfaceFlinger::removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + if (!listener) { + return BAD_VALUE; + } + + mTunnelModeEnabledReporter->removeListener(listener); + return NO_ERROR; +} + status_t SurfaceFlinger::getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) const { if (!displayToken || !outSupport) { @@ -1478,27 +1601,78 @@ status_t SurfaceFlinger::getDisplayBrightnessSupport(const sp<IBinder>& displayT return NO_ERROR; } -status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) { +status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, + const gui::DisplayBrightness& brightness) { if (!displayToken) { return BAD_VALUE; } - return promise::chain(schedule([=]() MAIN_THREAD { - if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { - return getHwComposer().setDisplayBrightness(*displayId, brightness); + return ftl::chain(schedule([=]() MAIN_THREAD { + if (const auto display = getDisplayDeviceLocked(displayToken)) { + if (enableSdrDimming) { + display->getCompositionDisplay() + ->setDisplayBrightness(brightness.sdrWhitePointNits, + brightness.displayBrightnessNits); + } + return getHwComposer().setDisplayBrightness(display->getPhysicalId(), + brightness.displayBrightness); } else { ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); - return promise::yield<status_t>(NAME_NOT_FOUND); + return ftl::yield<status_t>(NAME_NOT_FOUND); } })) .then([](std::future<status_t> task) { return task; }) .get(); } -status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) { - PowerHint powerHint = static_cast<PowerHint>(hintId); +status_t SurfaceFlinger::addHdrLayerInfoListener(const sp<IBinder>& displayToken, + const sp<gui::IHdrLayerInfoListener>& listener) { + if (!displayToken) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mStateLock); + + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { + return NAME_NOT_FOUND; + } + const auto displayId = display->getId(); + sp<HdrLayerInfoReporter>& hdrInfoReporter = mHdrLayerInfoListeners[displayId]; + if (!hdrInfoReporter) { + hdrInfoReporter = sp<HdrLayerInfoReporter>::make(); + } + hdrInfoReporter->addListener(listener); + + + mAddingHDRLayerInfoListener = true; + return OK; +} + +status_t SurfaceFlinger::removeHdrLayerInfoListener( + const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) { + if (!displayToken) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mStateLock); + + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { + return NAME_NOT_FOUND; + } + const auto displayId = display->getId(); + sp<HdrLayerInfoReporter>& hdrInfoReporter = mHdrLayerInfoListeners[displayId]; + if (hdrInfoReporter) { + hdrInfoReporter->removeListener(listener); + } + return OK; +} + +status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) { + Boost powerBoost = static_cast<Boost>(boostId); - if (powerHint == PowerHint::INTERACTION) { + if (powerBoost == Boost::INTERACTION) { mScheduler->notifyTouchEvent(); } @@ -1508,11 +1682,12 @@ status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) { // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) { + ISurfaceComposer::VsyncSource vsyncSource, + ISurfaceComposer::EventRegistrationFlags eventRegistration) { const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle; - return mScheduler->createDisplayEventConnection(handle, configChanged); + return mScheduler->createDisplayEventConnection(handle, eventRegistration); } void SurfaceFlinger::signalTransaction() { @@ -1533,23 +1708,23 @@ void SurfaceFlinger::signalRefresh() { } nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { - const auto displayId = getInternalDisplayIdLocked(); - if (!displayId || !getHwComposer().isConnected(*displayId)) { - return 0; + if (const auto display = getDefaultDisplayDeviceLocked()) { + return display->getVsyncPeriodFromHWC(); } - return getHwComposer().getDisplayVsyncPeriod(*displayId); + return 0; } -void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId, - int64_t timestamp, - std::optional<hal::VsyncPeriodNanos> vsyncPeriod) { - ATRACE_NAME("SF onVsync"); +void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp, + std::optional<hal::VsyncPeriodNanos> vsyncPeriod) { + ATRACE_CALL(); Mutex::Autolock lock(mStateLock); - // Ignore any vsyncs from a previous hardware composer. - if (sequenceId != getBE().mComposerSequenceId) { - return; + + if (const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId)) { + auto token = getPhysicalDisplayTokenLocked(*displayId); + auto display = getDisplayDeviceLocked(token); + display->onVsync(timestamp); } if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) { @@ -1564,7 +1739,7 @@ void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hal::HWDisplayId hwcDis bool periodFlushed = false; mScheduler->addResyncSample(timestamp, vsyncPeriod, &periodFlushed); if (periodFlushed) { - mVSyncModulator->onRefreshRateChangeCompleted(); + modulateVsync(&VsyncModulator::onRefreshRateChangeCompleted); } } @@ -1573,12 +1748,12 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -bool SurfaceFlinger::isDisplayConfigAllowed(HwcConfigIndexType configId) const { - return mRefreshRateConfigs->isConfigAllowed(configId); +bool SurfaceFlinger::isDisplayModeAllowed(DisplayModeId modeId) const { + return mRefreshRateConfigs->isModeAllowed(modeId); } void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, - Scheduler::ConfigEvent event) { + Scheduler::ModeEvent event) { const auto display = getDefaultDisplayDeviceLocked(); if (!display || mBootStage != BootStage::FINISHED) { return; @@ -1586,25 +1761,20 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, ATRACE_CALL(); // Don't do any updating if the current fps is the same as the new one. - if (!isDisplayConfigAllowed(refreshRate.getConfigId())) { - ALOGV("Skipping config %d as it is not part of allowed configs", - refreshRate.getConfigId().value()); + if (!isDisplayModeAllowed(refreshRate.getModeId())) { + ALOGV("Skipping mode %d as it is not part of allowed modes", + refreshRate.getModeId().value()); return; } - setDesiredActiveConfig({refreshRate.getConfigId(), event}); + setDesiredActiveMode({refreshRate.getModeId(), event}); } -void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId, - hal::Connection connection) { - ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId, +void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, + hal::Connection connection) { + ALOGI("%s(%" PRIu64 ", %s)", __func__, hwcDisplayId, connection == hal::Connection::CONNECTED ? "connected" : "disconnected"); - // Ignore events that do not have the right sequenceId. - if (sequenceId != getBE().mComposerSequenceId) { - return; - } - // 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 // the main thread with the state lock already held, so don't attempt to @@ -1621,63 +1791,49 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcD setTransactionFlags(eDisplayTransactionNeeded); } -void SurfaceFlinger::onVsyncPeriodTimingChangedReceived( - int32_t sequenceId, hal::HWDisplayId /*display*/, - const hal::VsyncPeriodChangeTimeline& updatedTimeline) { +void SurfaceFlinger::onComposerHalVsyncPeriodTimingChanged( + hal::HWDisplayId, const hal::VsyncPeriodChangeTimeline& timeline) { Mutex::Autolock lock(mStateLock); - if (sequenceId != getBE().mComposerSequenceId) { - return; - } - mScheduler->onNewVsyncPeriodChangeTimeline(updatedTimeline); + mScheduler->onNewVsyncPeriodChangeTimeline(timeline); } -void SurfaceFlinger::onSeamlessPossible(int32_t /*sequenceId*/, hal::HWDisplayId /*display*/) { - // TODO(b/142753666): use constraints when calling to setActiveConfigWithConstrains and +void SurfaceFlinger::onComposerHalSeamlessPossible(hal::HWDisplayId) { + // TODO(b/142753666): use constraints when calling to setActiveModeWithConstraints and // use this callback to know when to retry in case of SEAMLESS_NOT_POSSIBLE. } -void SurfaceFlinger::onRefreshReceived(int sequenceId, hal::HWDisplayId /*hwcDisplayId*/) { +void SurfaceFlinger::onComposerHalRefresh(hal::HWDisplayId) { Mutex::Autolock lock(mStateLock); - if (sequenceId != getBE().mComposerSequenceId) { - return; - } repaintEverythingForHWC(); } -void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) { +void SurfaceFlinger::setVsyncEnabled(bool enabled) { ATRACE_CALL(); - // Enable / Disable HWVsync from the main thread to avoid race conditions with - // display power state. - static_cast<void>(schedule([=]() MAIN_THREAD { setPrimaryVsyncEnabledInternal(enabled); })); -} - -void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) { - ATRACE_CALL(); - - mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE; + // On main thread to avoid race conditions with display power state. + static_cast<void>(schedule([=]() MAIN_THREAD { + mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE; - if (const auto displayId = getInternalDisplayIdLocked()) { - sp<DisplayDevice> display = getDefaultDisplayDeviceLocked(); - if (display && display->isPoweredOn()) { - getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState); + if (const auto display = getDefaultDisplayDeviceLocked(); + display && display->isPoweredOn()) { + getHwComposer().setVsyncEnabled(display->getPhysicalId(), mHWCVsyncPendingState); } - } + })); } -sp<Fence> SurfaceFlinger::previousFrameFence() { - // We are storing the last 2 present fences. If sf's phase offset is to be - // woken up before the actual vsync but targeting the next vsync, we need to check - // fence N-2 - return mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0] - : mPreviousPresentFences[1]; +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]; } bool SurfaceFlinger::previousFramePending(int graceTimeMs) { ATRACE_CALL(); - const sp<Fence>& fence = previousFrameFence(); + const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime; - if (fence == Fence::NO_FENCE) { + if (fence == FenceTime::NO_FENCE) { return false; } @@ -1688,28 +1844,25 @@ bool SurfaceFlinger::previousFramePending(int graceTimeMs) { } nsecs_t SurfaceFlinger::previousFramePresentTime() { - const sp<Fence>& fence = previousFrameFence(); + const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime; - if (fence == Fence::NO_FENCE) { + if (fence == FenceTime::NO_FENCE) { return Fence::SIGNAL_TIME_INVALID; } return fence->getSignalTime(); } -nsecs_t SurfaceFlinger::calculateExpectedPresentTime(nsecs_t now) const { - DisplayStatInfo stats; - mScheduler->getDisplayStatInfo(&stats); - const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(now); +nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) const { // Inflate the expected present time if we're targetting the next vsync. - return mVSyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod; + return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? stats.vsyncTime + : stats.vsyncTime + stats.vsyncPeriod; } -void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t expectedVSyncTime) { - ATRACE_CALL(); +void SurfaceFlinger::onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime) { switch (what) { case MessageQueue::INVALIDATE: { - onMessageInvalidate(expectedVSyncTime); + onMessageInvalidate(vsyncId, expectedVSyncTime); break; } case MessageQueue::REFRESH: { @@ -1719,9 +1872,7 @@ void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t expectedVSyncTime) } } -void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) { - ATRACE_CALL(); - +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 @@ -1729,20 +1880,25 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) { if (expectedVSyncTime >= frameStart) { mExpectedPresentTime = expectedVSyncTime; } else { - mExpectedPresentTime = mScheduler->getDispSyncExpectedPresentTime(frameStart); + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameStart); + mExpectedPresentTime = calculateExpectedPresentTime(stats); } const nsecs_t lastScheduledPresentTime = mScheduledPresentTime; mScheduledPresentTime = expectedVSyncTime; + 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)"); + // 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 // where present fence is just about to get signaled. const int graceTimeForPresentFenceMs = - (mPropagateBackpressure && - (mPropagateBackpressureClientComposition || !mHadClientComposition)) - ? 1 - : 0; + (mPropagateBackpressureClientComposition || !mHadClientComposition) ? 1 : 0; // Pending frames may trigger backpressure propagation. const TracedOrdinal<bool> framePending = {"PrevFramePending", @@ -1756,8 +1912,7 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) { // Add some slop to correct for drift. This should generally be // smaller than a typical frame duration, but should not be so small // that it reports reasonable drift as a missed frame. - DisplayStatInfo stats; - mScheduler->getDisplayStatInfo(&stats); + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime()); const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2; const nsecs_t previousPresentTime = previousFramePresentTime(); const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed", @@ -1773,10 +1928,6 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) { if (frameMissed) { mFrameMissedCount++; mTimeStats->incrementMissedFrames(); - if (mMissedFrameJankCount == 0) { - mMissedFrameJankStart = systemTime(); - } - mMissedFrameJankCount++; } if (hwcFrameMissed) { @@ -1787,73 +1938,52 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) { mGpuFrameMissedCount++; } - // If we are in the middle of a config change and the fence hasn't + // If we are in the middle of a mode change and the fence hasn't // fired yet just wait for the next invalidate - if (mSetActiveConfigPending) { + if (mSetActiveModePending) { if (framePending) { mEventQueue->invalidate(); return; } // We received the present fence from the HWC, so we assume it successfully updated - // the config, hence we update SF. - mSetActiveConfigPending = false; - ON_MAIN_THREAD(setActiveConfigInternal()); + // the mode, hence we update SF. + mSetActiveModePending = false; + ON_MAIN_THREAD(setActiveModeInternal()); } - if (framePending && mPropagateBackpressure) { + if (framePending) { if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) { signalLayerUpdate(); return; } } - // Our jank window is always at least 100ms since we missed a - // frame... - static constexpr nsecs_t kMinJankyDuration = - std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count(); - // ...but if it's larger than 1s then we missed the trace cutoff. - static constexpr nsecs_t kMaxJankyDuration = - std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count(); - nsecs_t jankDurationToUpload = -1; - // If we're in a user build then don't push any atoms - if (!mIsUserBuild && mMissedFrameJankCount > 0) { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - // Only report jank when the display is on, as displays in DOZE - // power mode may operate at a different frame rate than is - // reported in their config, which causes noticeable (but less - // severe) jank. - if (display && display->getPowerMode() == hal::PowerMode::ON) { - const nsecs_t currentTime = systemTime(); - const nsecs_t jankDuration = currentTime - mMissedFrameJankStart; - if (jankDuration > kMinJankyDuration && jankDuration < kMaxJankyDuration) { - jankDurationToUpload = jankDuration; - } - - // We either reported a jank event or we missed the trace - // window, so clear counters here. - if (jankDuration > kMinJankyDuration) { - mMissedFrameJankCount = 0; - mMissedFrameJankStart = 0; - } - } - } - if (mTracingEnabledChanged) { mTracingEnabled = mTracing.isEnabled(); mTracingEnabledChanged = false; } + if (mRefreshRateOverlaySpinner) { + if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) { + mRefreshRateOverlay->onInvalidate(); + } + } + bool refreshNeeded; { - ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled); + 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 (mTracingEnabled) { - mAddCompositionStateToTrace = - mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION); - if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) { + if (tracePreComposition) { + if (mVisibleRegionsDirty) { mTracing.notifyLocked("visibleRegionsDirty"); } } @@ -1868,14 +1998,13 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) { mScheduler->chooseRefreshRateForContent(); } - ON_MAIN_THREAD(performSetActiveConfig()); + ON_MAIN_THREAD(performSetActiveMode()); updateCursorAsync(); updateInputFlinger(); refreshNeeded |= mRepaintEverything; if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) { - mLastJankDuration = jankDurationToUpload; // Signal a refresh if a transaction modified the window state, // a new buffer was latched, or if HWC has requested a full // repaint @@ -1886,25 +2015,28 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) { // underestimated. mFrameStartTime = frameStart; } - signalRefresh(); + + // 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(); - uint32_t transactionFlags = peekTransactionFlags(); - - bool flushedATransaction = flushTransactionQueues(); + if (getTransactionFlags(eTransactionFlushNeeded)) { + flushTransactionQueues(); + } + uint32_t transactionFlags = peekTransactionFlags(); bool runHandleTransaction = - (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) || - flushedATransaction || - mForceTraversal; + ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal; if (runHandleTransaction) { handleTransaction(eTransactionMask); - } else { - getTransactionFlags(eTransactionFlushNeeded); } if (transactionFlushNeeded()) { @@ -1930,7 +2062,7 @@ void SurfaceFlinger::onMessageRefresh() { refreshArgs.layers.push_back(layerFE); }); refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); - for (sp<Layer> layer : mLayersWithQueuedFrames) { + for (auto layer : mLayersWithQueuedFrames) { if (auto layerFE = layer->getCompositionEngineLayerFE()) refreshArgs.layersWithQueuedFrames.push_back(layerFE); } @@ -1959,6 +2091,12 @@ void SurfaceFlinger::onMessageRefresh() { std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0); } + const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(mExpectedPresentTime); + const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration; + refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration; + refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime; + refreshArgs.nextInvalidateTime = mEventQueue->nextExpectedInvalidate(); + mGeometryInvalid = false; // Store the present time just before calling to the composition engine so we could notify @@ -1975,7 +2113,7 @@ void SurfaceFlinger::onMessageRefresh() { postFrame(); postComposition(); - const bool prevFrameHadDeviceComposition = mHadDeviceComposition; + const bool prevFrameHadClientComposition = mHadClientComposition; mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) { const auto& state = pair.second->getCompositionDisplay()->getState(); @@ -1990,23 +2128,28 @@ void SurfaceFlinger::onMessageRefresh() { const auto& state = pair.second->getCompositionDisplay()->getState(); return state.reusedClientComposition; }); - - // Only report a strategy change if we move in and out of composition with hw overlays - if (prevFrameHadDeviceComposition != mHadDeviceComposition) { + // Only report a strategy change if we move in and out of client composition + if (prevFrameHadClientComposition != mHadClientComposition) { mTimeStats->incrementCompositionStrategyChanges(); } // TODO: b/160583065 Enable skip validation when SF caches all client composition layers - mVSyncModulator->onRefreshed(mHadClientComposition || mReusedClientComposition); + const bool usedGpuComposition = mHadClientComposition || mReusedClientComposition; + modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition); mLayersWithQueuedFrames.clear(); - if (mVisibleRegionsDirty) { - mVisibleRegionsDirty = false; - if (mTracingEnabled && mAddCompositionStateToTrace) { + if (mTracingEnabled && mTracePostComposition) { + // This may block if SurfaceTracing is running in sync mode. + if (mVisibleRegionsDirty) { mTracing.notify("visibleRegionsDirty"); + } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) { + mTracing.notify("bufferLatched"); } } + mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp + mVisibleRegionsDirty = false; + if (mCompositionEngine->needsAnotherUpdate()) { signalLayerUpdate(); } @@ -2016,6 +2159,9 @@ bool SurfaceFlinger::handleMessageInvalidate() { ATRACE_CALL(); bool refreshNeeded = handlePageFlip(); + // Send on commit callbacks + mTransactionCallbackInvoker.sendCallbacks(); + if (mVisibleRegionsDirty) { computeLayerBounds(); } @@ -2059,12 +2205,12 @@ void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats, nsecs_t compositeToPresentLatency) { // Integer division and modulo round toward 0 not -inf, so we need to // treat negative and positive offsets differently. - nsecs_t idealLatency = (mPhaseConfiguration->getCurrentOffsets().late.sf > 0) + nsecs_t idealLatency = (mVsyncConfiguration->getCurrentConfigs().late.sfOffset > 0) ? (stats.vsyncPeriod - - (mPhaseConfiguration->getCurrentOffsets().late.sf % stats.vsyncPeriod)) - : ((-mPhaseConfiguration->getCurrentOffsets().late.sf) % stats.vsyncPeriod); + (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % stats.vsyncPeriod)) + : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % stats.vsyncPeriod); - // Just in case mPhaseConfiguration->getCurrentOffsets().late.sf == -vsyncInterval. + // Just in case mVsyncConfiguration->getCurrentConfigs().late.sf == -vsyncInterval. if (idealLatency <= 0) { idealLatency = stats.vsyncPeriod; } @@ -2074,7 +2220,7 @@ void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats, // Reducing jitter is important if an app attempts to extrapolate // something (such as user input) to an accurate diasplay time. // Snapping also allows an app to precisely calculate - // mPhaseConfiguration->getCurrentOffsets().late.sf with (presentLatency % interval). + // mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval). nsecs_t bias = stats.vsyncPeriod / 2; int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod; nsecs_t snappedCompositeToPresentLatency = @@ -2086,16 +2232,10 @@ void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats, getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency; } -void SurfaceFlinger::postComposition() -{ +void SurfaceFlinger::postComposition() { ATRACE_CALL(); ALOGV("postComposition"); - nsecs_t dequeueReadyTime = systemTime(); - for (auto& layer : mLayersWithQueuedFrames) { - layer->releasePendingBuffer(dequeueReadyTime); - } - const auto* display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()).get(); getBE().mGlCompositionDoneTimeline.updateSignalTimes(); @@ -2112,42 +2252,113 @@ void SurfaceFlinger::postComposition() getBE().mDisplayTimeline.updateSignalTimes(); mPreviousPresentFences[1] = mPreviousPresentFences[0]; - mPreviousPresentFences[0] = - display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE; - auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]); - getBE().mDisplayTimeline.push(presentFenceTime); + 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); - DisplayStatInfo stats; - mScheduler->getDisplayStatInfo(&stats); + nsecs_t now = systemTime(); + + // Set presentation information before calling Layer::releasePendingBuffer, such that jank + // information from previous' frame classification is already available when sending jank info + // to clients, so they get jank classification as early as possible. + mFrameTimeline->setSfPresent(/* sfPresentTime */ now, mPreviousPresentFences[0].fenceTime, + glCompositionDoneFenceTime); + + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now); // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, // but that should be okay since updateCompositorTiming has snapping logic. updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(), - presentFenceTime); + mPreviousPresentFences[0].fenceTime); CompositorTiming compositorTiming; { std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); compositorTiming = getBE().mCompositorTiming; } - mDrawingState.traverse([&](Layer* layer) { - const bool frameLatched = layer->onPostComposition(display, glCompositionDoneFenceTime, - presentFenceTime, compositorTiming); + for (const auto& layer: mLayersWithQueuedFrames) { + const bool frameLatched = + 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>>> + hdrInfoListeners; + bool haveNewListeners = false; + { + Mutex::Autolock lock(mStateLock); + if (mFpsReporter) { + mFpsReporter->dispatchLayerFps(); + } + + if (mTunnelModeEnabledReporter) { + mTunnelModeEnabledReporter->updateTunnelModeStatus(); + } + hdrInfoListeners.reserve(mHdrLayerInfoListeners.size()); + for (const auto& [displayId, reporter] : mHdrLayerInfoListeners) { + if (reporter && reporter->hasListeners()) { + if (const auto display = getDisplayDeviceLocked(displayId)) { + hdrInfoListeners.emplace_back(display->getCompositionDisplay(), reporter); + } + } + } + haveNewListeners = mAddingHDRLayerInfoListener; // grab this with state lock + mAddingHDRLayerInfoListener = false; + } + + if (haveNewListeners || mSomeDataspaceChanged || mVisibleRegionsWereDirtyThisFrame) { + for (auto& [compositionDisplay, listener] : hdrInfoListeners) { + HdrLayerInfoReporter::HdrLayerInfo info; + 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) { + const auto* outputLayer = + compositionDisplay->getOutputLayerForLayer(layerFe); + if (outputLayer) { + info.numberOfHdrLayers++; + const auto displayFrame = outputLayer->getState().displayFrame; + const int32_t area = displayFrame.width() * displayFrame.height(); + if (area > maxArea) { + maxArea = area; + info.maxW = displayFrame.width(); + info.maxH = displayFrame.height(); + } + } + } + } + }); + listener->dispatchHdrLayerInfo(info); + } + } - mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]); - mTransactionCompletedThread.sendCallbacks(); + mSomeDataspaceChanged = false; + mVisibleRegionsWereDirtyThisFrame = false; + + mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence); + mTransactionCallbackInvoker.sendCallbacks(); if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON && - presentFenceTime->isValid()) { - mScheduler->addPresentFence(presentFenceTime); + mPreviousPresentFences[0].fenceTime->isValid()) { + mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime); } - const bool isDisplayConnected = display && getHwComposer().isConnected(*display->getId()); + const bool isDisplayConnected = + display && getHwComposer().isConnected(display->getPhysicalId()); if (!hasSyncFramework) { if (isDisplayConnected && display->isPoweredOn()) { @@ -2158,13 +2369,12 @@ void SurfaceFlinger::postComposition() if (mAnimCompositionPending) { mAnimCompositionPending = false; - if (presentFenceTime->isValid()) { - mAnimFrameTracker.setActualPresentFence( - std::move(presentFenceTime)); + if (mPreviousPresentFences[0].fenceTime->isValid()) { + mAnimFrameTracker.setActualPresentFence(mPreviousPresentFences[0].fenceTime); } else if (isDisplayConnected) { // The HWC doesn't support present fences, so use the refresh // timestamp instead. - const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(*display->getId()); + const nsecs_t presentTime = display->getRefreshTimestamp(); mAnimFrameTracker.setActualPresentTime(presentTime); } mAnimFrameTracker.advanceFrame(); @@ -2179,20 +2389,12 @@ void SurfaceFlinger::postComposition() mTimeStats->incrementClientCompositionReusedFrames(); } - mTimeStats->setPresentFenceGlobal(presentFenceTime); + mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime); const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle); const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle); mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections); - if (mLastJankDuration > 0) { - ATRACE_NAME("Jank detected"); - const int32_t jankyDurationMillis = mLastJankDuration / (1000 * 1000); - android::util::stats_write(android::util::DISPLAY_JANK_REPORTED, jankyDurationMillis, - mMissedFrameJankCount); - mLastJankDuration = -1; - } - if (isDisplayConnected && !display->isPoweredOn()) { return; } @@ -2232,10 +2434,6 @@ void SurfaceFlinger::postComposition() } } - if (mLumaSampling && mRegionSamplingThread) { - mRegionSamplingThread->notifyNewContent(); - } - // Even though ATRACE_INT64 already checks if tracing is enabled, it doesn't prevent the // side-effect of getTotalSize(), so we check that again here if (ATRACE_ENABLED()) { @@ -2245,7 +2443,7 @@ void SurfaceFlinger::postComposition() } FloatRect SurfaceFlinger::getLayerClipBoundsForDisplay(const DisplayDevice& displayDevice) const { - return displayDevice.getViewport().toFloatRect(); + return displayDevice.getLayerStackSpaceRect().toFloatRect(); } void SurfaceFlinger::computeLayerBounds() { @@ -2266,7 +2464,7 @@ void SurfaceFlinger::computeLayerBounds() { void SurfaceFlinger::postFrame() { const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - if (display && getHwComposer().isConnected(*display->getId())) { + if (display && getHwComposer().isConnected(display->getPhysicalId())) { uint32_t flipCount = display->getPageFlipCount(); if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { logFrameStats(); @@ -2274,8 +2472,7 @@ void SurfaceFlinger::postFrame() { } } -void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) -{ +void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { ATRACE_CALL(); // here we keep a copy of the drawing state (that is the state that's @@ -2293,52 +2490,134 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) // with mStateLock held to guarantee that mCurrentState won't change // until the transaction is committed. - mVSyncModulator->onTransactionHandled(); + modulateVsync(&VsyncModulator::onTransactionCommit); transactionFlags = getTransactionFlags(eTransactionMask); handleTransactionLocked(transactionFlags); mDebugInTransaction = 0; - invalidateHwcGeometry(); // here the transaction has been committed } +void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes, + DisplayModePtr& outActiveMode) const { + std::vector<HWComposer::HWCDisplayMode> hwcModes; + std::optional<hal::HWDisplayId> activeModeHwcId; + bool activeModeIsSupported; + int attempt = 0; + constexpr int kMaxAttempts = 3; + do { + hwcModes = getHwComposer().getModes(displayId); + 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, + "After %d attempts HWC still returns an active mode which is not" + " 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; + } + } + + DisplayModes newModes; + int32_t nextModeId = largestUsedModeId + 1; + for (const auto& hwcMode : hwcModes) { + newModes.push_back(DisplayMode::Builder(hwcMode.hwcId) + .setId(DisplayModeId{nextModeId++}) + .setWidth(hwcMode.width) + .setHeight(hwcMode.height) + .setVsyncPeriod(hwcMode.vsyncPeriod) + .setDpiX(hwcMode.dpiX) + .setDpiY(hwcMode.dpiY) + .setGroup(hwcMode.configGroup) + .build()); + } + + const bool modesAreSame = + std::equal(newModes.begin(), newModes.end(), oldModes.begin(), oldModes.end(), + [](DisplayModePtr left, DisplayModePtr right) { + return left->equalsExceptDisplayModeId(right); + }); + + if (modesAreSame) { + // The supported modes have not changed, keep the old IDs. + outModes = oldModes; + } else { + outModes = newModes; + } + + outActiveMode = *std::find_if(outModes.begin(), outModes.end(), + [activeModeHwcId](const DisplayModePtr& mode) { + return mode->getHwcId() == *activeModeHwcId; + }); +} + void SurfaceFlinger::processDisplayHotplugEventsLocked() { for (const auto& event : mPendingHotplugEvents) { - const std::optional<DisplayIdentificationInfo> info = + std::optional<DisplayIdentificationInfo> info = getHwComposer().onHotplug(event.hwcDisplayId, event.connection); if (!info) { continue; } - const DisplayId displayId = info->id; + const auto displayId = info->id; const auto it = mPhysicalDisplayTokens.find(displayId); if (event.connection == hal::Connection::CONNECTED) { + DisplayModes supportedModes; + DisplayModePtr activeMode; + loadDisplayModes(displayId, supportedModes, activeMode); + if (it == mPhysicalDisplayTokens.end()) { ALOGV("Creating display %s", to_string(displayId).c_str()); - if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { - initScheduler(displayId); - } - DisplayDeviceState state; - state.physical = {displayId, getHwComposer().getDisplayConnectionType(displayId), - event.hwcDisplayId}; + state.physical = {.id = displayId, + .type = getHwComposer().getDisplayConnectionType(displayId), + .hwcDisplayId = event.hwcDisplayId, + .deviceProductInfo = std::move(info->deviceProductInfo), + .supportedModes = std::move(supportedModes), + .activeMode = activeMode}; state.isSecure = true; // All physical displays are currently considered secure. - state.displayName = info->name; + state.displayName = std::move(info->name); sp<IBinder> token = new BBinder(); mCurrentState.displays.add(token, state); mPhysicalDisplayTokens.emplace(displayId, std::move(token)); + if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { + initScheduler(state); + } + 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; + state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId + state.physical->supportedModes = std::move(supportedModes); + state.physical->activeMode = activeMode; + if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) { + state.physical->deviceProductInfo = std::move(info->deviceProductInfo); + } } } else { ALOGV("Removing display %s", to_string(displayId).c_str()); @@ -2359,6 +2638,8 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { } void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) { + ALOGI("Dispatching display hotplug event displayId=%s, connected=%d", + to_string(displayId).c_str(), connected); mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected); mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected); } @@ -2369,8 +2650,7 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer) { - auto displayId = compositionDisplay->getDisplayId(); - DisplayDeviceCreationArgs creationArgs(this, displayToken, compositionDisplay); + DisplayDeviceCreationArgs creationArgs(this, getHwComposer(), displayToken, compositionDisplay); creationArgs.sequenceId = state.sequenceId; creationArgs.isSecure = state.isSecure; creationArgs.displaySurface = displaySurface; @@ -2379,28 +2659,29 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( if (const auto& physical = state.physical) { creationArgs.connectionType = physical->type; + creationArgs.supportedModes = physical->supportedModes; } - const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked(); - creationArgs.isPrimary = isInternalDisplay; + if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) { + creationArgs.isPrimary = id == getInternalDisplayIdLocked(); - if (useColorManagement && displayId) { - std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId); - for (ColorMode colorMode : modes) { - if (isWideColorMode(colorMode)) { - creationArgs.hasWideColorGamut = true; - } + if (useColorManagement) { + std::vector<ColorMode> modes = getHwComposer().getColorModes(*id); + for (ColorMode colorMode : modes) { + if (isWideColorMode(colorMode)) { + creationArgs.hasWideColorGamut = true; + } - std::vector<RenderIntent> renderIntents = - getHwComposer().getRenderIntents(*displayId, colorMode); - creationArgs.hwcColorModes.emplace(colorMode, renderIntents); + std::vector<RenderIntent> renderIntents = + getHwComposer().getRenderIntents(*id, colorMode); + creationArgs.hwcColorModes.emplace(colorMode, renderIntents); + } } } - if (displayId) { - getHwComposer().getHdrCapabilities(*displayId, &creationArgs.hdrCapabilities); - creationArgs.supportedPerFrameMetadata = - getHwComposer().getSupportedPerFrameMetadata(*displayId); + if (const auto id = HalDisplayId::tryCast(compositionDisplay->getId())) { + getHwComposer().getHdrCapabilities(*id, &creationArgs.hdrCapabilities); + creationArgs.supportedPerFrameMetadata = getHwComposer().getSupportedPerFrameMetadata(*id); } auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer); @@ -2415,16 +2696,14 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( } creationArgs.physicalOrientation = - isInternalDisplay ? internalDisplayOrientation : ui::ROTATION_0; + creationArgs.isPrimary ? internalDisplayOrientation : ui::ROTATION_0; // virtual displays are always considered enabled creationArgs.initialPowerMode = state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF; sp<DisplayDevice> display = getFactory().createDisplayDevice(creationArgs); - if (maxFrameBufferAcquiredBuffers >= 3) { - nativeWindowSurface->preallocateBuffers(); - } + nativeWindowSurface->preallocateBuffers(); ColorMode defaultColorMode = ColorMode::NATIVE; Dataspace defaultDataSpace = Dataspace::UNKNOWN; @@ -2437,13 +2716,13 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); if (!state.isVirtual()) { - LOG_ALWAYS_FATAL_IF(!displayId); - auto activeConfigId = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(*displayId)); - display->setActiveConfig(activeConfigId); + display->setActiveMode(state.physical->activeMode->getId()); + display->setDeviceProductInfo(state.physical->deviceProductInfo); } display->setLayerStack(state.layerStack); - display->setProjection(state.orientation, state.viewport, state.frame); + display->setProjection(state.orientation, state.layerStackSpaceRect, + state.orientedDisplaySpaceRect); display->setDisplayName(state.displayName); return display; @@ -2451,24 +2730,20 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState& state) { - int width = 0; - int height = 0; + ui::Size resolution(0, 0); ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN); if (state.physical) { - const auto& activeConfig = - getCompositionEngine().getHwComposer().getActiveConfig(state.physical->id); - width = activeConfig->getWidth(); - height = activeConfig->getHeight(); + resolution = state.physical->activeMode->getSize(); pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888); } else if (state.surface != nullptr) { - int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width); + int status = state.surface->query(NATIVE_WINDOW_WIDTH, &resolution.width); ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); - status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height); + status = state.surface->query(NATIVE_WINDOW_HEIGHT, &resolution.height); ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); - int intPixelFormat; - status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat); + int format; + status = state.surface->query(NATIVE_WINDOW_FORMAT, &format); ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); - pixelFormat = static_cast<ui::PixelFormat>(intPixelFormat); + pixelFormat = static_cast<ui::PixelFormat>(format); } else { // Virtual displays without a surface are dormant: // they have external state (layer stack, projection, @@ -2478,16 +2753,19 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, compositionengine::DisplayCreationArgsBuilder builder; if (const auto& physical = state.physical) { - builder.setPhysical({physical->id, physical->type}); + builder.setId(physical->id); + builder.setConnectionType(physical->type); + } else { + builder.setId(acquireVirtualDisplay(resolution, pixelFormat, state.layerStack)); } - builder.setPixels(ui::Size(width, height)); - builder.setPixelFormat(pixelFormat); + + builder.setPixels(resolution); builder.setIsSecure(state.isSecure); builder.setLayerStackId(state.layerStack); builder.setPowerAdvisor(&mPowerAdvisor); - builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays); builder.setName(state.displayName); - const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); + auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); + compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled); sp<compositionengine::DisplaySurface> displaySurface; sp<IGraphicBufferProducer> producer; @@ -2495,54 +2773,70 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, sp<IGraphicBufferConsumer> bqConsumer; getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false); - std::optional<DisplayId> displayId = compositionDisplay->getId(); - if (state.isVirtual()) { - sp<VirtualDisplaySurface> vds = - new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, bqProducer, - bqConsumer, state.displayName); - - displaySurface = vds; - producer = vds; + const auto displayId = VirtualDisplayId::tryCast(compositionDisplay->getId()); + LOG_FATAL_IF(!displayId); + auto surface = sp<VirtualDisplaySurface>::make(getHwComposer(), *displayId, state.surface, + bqProducer, bqConsumer, state.displayName); + displaySurface = surface; + producer = std::move(surface); } else { ALOGE_IF(state.surface != nullptr, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); - - LOG_ALWAYS_FATAL_IF(!displayId); - displaySurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer, - maxGraphicsWidth, maxGraphicsHeight); + const auto displayId = PhysicalDisplayId::tryCast(compositionDisplay->getId()); + LOG_FATAL_IF(!displayId); + displaySurface = + sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqConsumer, + state.physical->activeMode->getSize(), + ui::Size(maxGraphicsWidth, maxGraphicsHeight)); producer = bqProducer; } LOG_FATAL_IF(!displaySurface); - const auto display = setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state, - displaySurface, producer); + const auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay), + state, displaySurface, producer); mDisplays.emplace(displayToken, display); if (!state.isVirtual()) { - LOG_FATAL_IF(!displayId); - dispatchDisplayHotplugEvent(displayId->value, true); + dispatchDisplayHotplugEvent(display->getPhysicalId(), true); } if (display->isPrimary()) { mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight()); + getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize()); } } void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { - if (const auto display = getDisplayDeviceLocked(displayToken)) { - // Save display ID before disconnecting. - const auto displayId = display->getId(); + auto display = getDisplayDeviceLocked(displayToken); + if (display) { display->disconnect(); - if (!display->isVirtual()) { - LOG_FATAL_IF(!displayId); - dispatchDisplayHotplugEvent(displayId->value, false); + if (display->isVirtual()) { + releaseVirtualDisplay(display->getVirtualId()); + } else { + dispatchDisplayHotplugEvent(display->getPhysicalId(), false); } } mDisplays.erase(displayToken); + + if (display && display->isVirtual()) { + static_cast<void>(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. + // With blast, the IGBP that is passed to the VirtualDisplaySurface is owned by the + // client. When the IGBP is disconnected, its buffer cache in SF will be cleared + // via SurfaceComposerClient::doUncacheBufferTransaction. This call from the client + // ends up running on the main thread causing a deadlock since setTransactionstate + // will try to acquire the mStateLock. Instead we extend the lifetime of + // DisplayDevice and destroy it in the main thread without holding the mStateLock. + // The display will be disconnected and removed from the mDisplays list so it will + // not be accessible. + })); + } } void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, @@ -2550,19 +2844,43 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, const DisplayDeviceState& drawingState) { const sp<IBinder> currentBinder = IInterface::asBinder(currentState.surface); const sp<IBinder> drawingBinder = IInterface::asBinder(drawingState.surface); + + // Recreate the DisplayDevice if the surface or sequence ID changed. if (currentBinder != drawingBinder || currentState.sequenceId != drawingState.sequenceId) { - // changing the surface is like destroying and recreating the DisplayDevice + getRenderEngine().cleanFramebufferCache(); + if (const auto display = getDisplayDeviceLocked(displayToken)) { display->disconnect(); + if (display->isVirtual()) { + releaseVirtualDisplay(display->getVirtualId()); + } } + mDisplays.erase(displayToken); + if (const auto& physical = currentState.physical) { getHwComposer().allocatePhysicalDisplay(physical->hwcDisplayId, physical->id); } + processDisplayAdded(displayToken, currentState); + if (currentState.physical) { const auto display = getDisplayDeviceLocked(displayToken); setPowerModeInternal(display, hal::PowerMode::ON); + + // TODO(b/175678251) Call a listener instead. + if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { + mRefreshRateConfigs->updateDisplayModes(currentState.physical->supportedModes, + currentState.physical->activeMode->getId()); + mVsyncConfiguration->reset(); + const Fps refreshRate = currentState.physical->activeMode->getFps(); + updatePhaseConfiguration(refreshRate); + mRefreshRateStats->setRefreshRate(refreshRate); + + if (mRefreshRateOverlay) { + mRefreshRateOverlay->reset(); + } + } } return; } @@ -2572,10 +2890,13 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, display->setLayerStack(currentState.layerStack); } if ((currentState.orientation != drawingState.orientation) || - (currentState.viewport != drawingState.viewport) || - (currentState.frame != drawingState.frame)) { - display->setProjection(currentState.orientation, currentState.viewport, - currentState.frame); + (currentState.layerStackSpaceRect != drawingState.layerStackSpaceRect) || + (currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) { + display->setProjection(currentState.orientation, currentState.layerStackSpaceRect, + currentState.orientedDisplaySpaceRect); + if (display->isPrimary()) { + mDefaultDisplayTransformHint = display->getTransformHint(); + } } if (currentState.width != drawingState.width || currentState.height != drawingState.height) { @@ -2632,45 +2953,22 @@ void SurfaceFlinger::processDisplayChangesLocked() { mDrawingState.displays = mCurrentState.displays; } -void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) -{ - const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); - - // Notify all layers of available frames - mCurrentState.traverse([expectedPresentTime](Layer* layer) { - layer->notifyAvailableFrames(expectedPresentTime); - }); - - /* - * Traversal of the children - * (perform the transaction for each of them if needed) - */ - - if ((transactionFlags & eTraversalNeeded) || mForceTraversal) { - mForceTraversal = false; - mCurrentState.traverse([&](Layer* layer) { - uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); - if (!trFlags) return; - - const uint32_t flags = layer->doTransaction(0); - if (flags & Layer::eVisibleRegion) - mVisibleRegionsDirty = true; - - if (flags & Layer::eInputInfoChanged) { - mInputInfoChanged = true; - } - }); - } - - /* - * Perform display own transactions if needed - */ - - if (transactionFlags & eDisplayTransactionNeeded) { +void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { + // Commit display transactions + const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; + if (displayTransactionNeeded) { processDisplayChangesLocked(); processDisplayHotplugEventsLocked(); } + mForceTraversal = false; + mForceTransactionDisplayChange = displayTransactionNeeded; + if (mSomeChildrenChanged) { + mVisibleRegionsDirty = true; + mSomeChildrenChanged = false; + } + + // 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 @@ -2764,7 +3062,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) }); } - commitInputWindowCommands(); commitTransaction(); } @@ -2783,34 +3080,49 @@ void SurfaceFlinger::updateInputFlinger() { setInputWindowsFinished(); } + for (const auto& focusRequest : mInputWindowCommands.focusRequests) { + mInputFlinger->setFocusedWindow(focusRequest); + } mInputWindowCommands.clear(); } +bool enablePerWindowInputRotation() { + static bool value = + android::base::GetBoolProperty("persist.debug.per_window_input_rotation", false); + return value; +} + void SurfaceFlinger::updateInputWindowInfo() { - std::vector<InputWindowInfo> inputHandles; + std::vector<InputWindowInfo> inputInfos; mDrawingState.traverseInReverseZOrder([&](Layer* layer) { - if (layer->needsInputInfo()) { - // When calculating the screen bounds we ignore the transparent region since it may - // result in an unwanted offset. - inputHandles.push_back(layer->fillInputInfo()); + if (!layer->needsInputInfo()) return; + sp<DisplayDevice> display; + if (enablePerWindowInputRotation()) { + for (const auto& pair : ON_MAIN_THREAD(mDisplays)) { + const auto& displayDevice = pair.second; + if (!displayDevice->getCompositionDisplay() + ->belongsInOutput(layer->getLayerStack(), + layer->getPrimaryDisplayOnly())) { + continue; + } + display = displayDevice; + } } + // When calculating the screen bounds we ignore the transparent region since it may + // result in an unwanted offset. + inputInfos.push_back(layer->fillInputInfo(display)); }); - mInputFlinger->setInputWindows(inputHandles, - mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener - : nullptr); -} - -void SurfaceFlinger::commitInputWindowCommands() { - mInputWindowCommands.merge(mPendingInputWindowCommands); - mPendingInputWindowCommands.clear(); + mInputFlinger->setInputWindows(inputInfos, + mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener + : nullptr); } void SurfaceFlinger::updateCursorAsync() { compositionengine::CompositionRefreshArgs refreshArgs; for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { - if (display->getId()) { + if (HalDisplayId::tryCast(display->getId())) { refreshArgs.outputs.push_back(display->getCompositionDisplay()); } } @@ -2818,75 +3130,110 @@ void SurfaceFlinger::updateCursorAsync() { mCompositionEngine->updateCursorAsync(refreshArgs); } -void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, - Scheduler::ConfigEvent event) { +void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, Scheduler::ModeEvent 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 - // Sheduler::chooseRefreshRateForContent + // Scheduler::chooseRefreshRateForContent ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); changeRefreshRateLocked(refreshRate, event); } -void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { +void SurfaceFlinger::triggerOnFrameRateOverridesChanged() { + PhysicalDisplayId displayId = [&]() { + ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); + return getDefaultDisplayDeviceLocked()->getPhysicalId(); + }(); + + mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId); +} + +void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) { if (mScheduler) { // In practice it's not allowed to hotplug in/out the primary display once it's been // connected during startup, but some tests do it, so just warn and return. ALOGW("Can't re-init scheduler"); return; } - - auto currentConfig = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(primaryDisplayId)); + const auto displayId = displayState.physical->id; + scheduler::RefreshRateConfigs::Config config = + {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false), + .frameRateMultipleThreshold = + base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0)}; mRefreshRateConfigs = - std::make_unique<scheduler::RefreshRateConfigs>(getHwComposer().getConfigs( - primaryDisplayId), - currentConfig); - mRefreshRateStats = - std::make_unique<scheduler::RefreshRateStats>(*mRefreshRateConfigs, *mTimeStats, - currentConfig, hal::PowerMode::OFF); - mRefreshRateStats->setConfigMode(currentConfig); + std::make_unique<scheduler::RefreshRateConfigs>(displayState.physical->supportedModes, + displayState.physical->activeMode + ->getId(), + config); + const auto currRefreshRate = displayState.physical->activeMode->getFps(); + mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate, + hal::PowerMode::OFF); - mPhaseConfiguration = getFactory().createPhaseConfiguration(*mRefreshRateConfigs); + mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate); + mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs()); // start the EventThread - mScheduler = - getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, - *mRefreshRateConfigs, *this); + mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this); + const auto configs = mVsyncConfiguration->getCurrentConfigs(); + const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs(); mAppConnectionHandle = - mScheduler->createConnection("app", mPhaseConfiguration->getCurrentOffsets().late.app, + mScheduler->createConnection("app", mFrameTimeline->getTokenManager(), + /*workDuration=*/configs.late.appWorkDuration, + /*readyDuration=*/configs.late.sfWorkDuration, impl::EventThread::InterceptVSyncsCallback()); mSfConnectionHandle = - mScheduler->createConnection("sf", mPhaseConfiguration->getCurrentOffsets().late.sf, + mScheduler->createConnection("appSf", mFrameTimeline->getTokenManager(), + /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod), + /*readyDuration=*/configs.late.sfWorkDuration, [this](nsecs_t timestamp) { mInterceptor->saveVSyncEvent(timestamp); }); - mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); - mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle, - mPhaseConfiguration->getCurrentOffsets()); + mEventQueue->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(), + configs.late.sfWorkDuration); mRegionSamplingThread = - new RegionSamplingThread(*this, *mScheduler, - RegionSamplingThread::EnvironmentTimingTunables()); - // Dispatch a config change request for the primary display on scheduler + new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables()); + mFpsReporter = new FpsReporter(*mFrameTimeline, *this); + // Dispatch a mode change request for the primary display on scheduler // initialization, so that the EventThreads always contain a reference to a // prior configuration. // // This is a bit hacky, but this avoids a back-pointer into the main SF // classes from EventThread, and there should be no run-time binder cost // anyway since there are no connected apps at this point. - const nsecs_t vsyncPeriod = - mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig).getVsyncPeriod(); - mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, primaryDisplayId.value, - currentConfig, vsyncPeriod); -} - -void SurfaceFlinger::commitTransaction() -{ + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, displayId, + displayState.physical->activeMode->getId(), + vsyncPeriod); + 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) { + mVsyncConfiguration->setRefreshRateFps(refreshRate); + setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()), + refreshRate.getPeriodNsecs()); +} + +void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config, + nsecs_t vsyncPeriod) { + mScheduler->setDuration(mAppConnectionHandle, + /*workDuration=*/config.appWorkDuration, + /*readyDuration=*/config.sfWorkDuration); + mScheduler->setDuration(mSfConnectionHandle, + /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod), + /*readyDuration=*/config.sfWorkDuration); + mEventQueue->setDuration(config.sfWorkDuration); +} + +void SurfaceFlinger::commitTransaction() { + ATRACE_CALL(); commitTransactionLocked(); - mTransactionPending = false; + signalSynchronousTransactions(CountDownLatch::eSyncTransaction); mAnimTransactionPending = false; - mTransactionCV.broadcast(); } void SurfaceFlinger::commitTransactionLocked() { @@ -2918,18 +3265,16 @@ void SurfaceFlinger::commitTransactionLocked() { // clear the "changed" flags in current state mCurrentState.colorMatrixChanged = false; - mDrawingState.traverse([&](Layer* layer) { - layer->commitChildList(); - - // If the layer can be reached when traversing mDrawingState, then the layer is no - // longer offscreen. Remove the layer from the offscreenLayer set. - if (mOffscreenLayers.count(layer)) { - mOffscreenLayers.erase(layer); + if (mVisibleRegionsDirty) { + for (const auto& rootLayer : mDrawingState.layersSortedByZ) { + rootLayer->commitChildList(); } - }); + } commitOffscreenLayers(); - mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); }); + if (mNumClones > 0) { + mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); }); + } } void SurfaceFlinger::commitOffscreenLayers() { @@ -2953,8 +3298,7 @@ void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Re } } -bool SurfaceFlinger::handlePageFlip() -{ +bool SurfaceFlinger::handlePageFlip() { ATRACE_CALL(); ALOGV("handlePageFlip"); @@ -2976,18 +3320,26 @@ 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) { - if (layer->hasReadyFrame()) { + uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); + if (trFlags || mForceTransactionDisplayChange) { + const uint32_t flags = layer->doTransaction(0); + if (flags & Layer::eVisibleRegion) + mVisibleRegionsDirty = true; + } + + if (layer->hasReadyFrame()) { frameQueued = true; if (layer->shouldPresentNow(expectedPresentTime)) { - mLayersWithQueuedFrames.push_back(layer); + mLayersWithQueuedFrames.emplace(layer); } else { ATRACE_NAME("!layer->shouldPresentNow()"); layer->useEmptyDamage(); } - } else { + } else { layer->useEmptyDamage(); } }); + mForceTransactionDisplayChange = false; // The client can continue submitting buffers for offscreen layers, but they will not // be shown on screen. Therefore, we need to latch and release buffers of offscreen @@ -3002,7 +3354,7 @@ bool SurfaceFlinger::handlePageFlip() // writes to Layer current state. See also b/119481871 Mutex::Autolock lock(mStateLock); - for (auto& layer : mLayersWithQueuedFrames) { + for (const auto& layer : mLayersWithQueuedFrames) { if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) { mLayersPendingRefresh.push_back(layer); } @@ -3028,77 +3380,55 @@ bool SurfaceFlinger::handlePageFlip() mBootStage = BootStage::BOOTANIMATION; } - mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); }); + if (mNumClones > 0) { + mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); }); + } // Only continue with the refresh if there is actually new work to do return !mLayersWithQueuedFrames.empty() && newDataLatched; } -void SurfaceFlinger::invalidateHwcGeometry() -{ +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 addToCurrentState, + const sp<Layer>& parentLayer, bool addToRoot, uint32_t* outTransformHint) { - // add this layer to the current state list - { - Mutex::Autolock _l(mStateLock); - sp<Layer> parent; - if (parentHandle != nullptr) { - parent = fromHandleLocked(parentHandle).promote(); - if (parent == nullptr) { - return NAME_NOT_FOUND; - } - } else { - parent = parentLayer; - } - - if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { - ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), - ISurfaceComposer::MAX_LAYERS); - return NO_MEMORY; - } - - mLayersByLocalBinderToken.emplace(handle->localBinder(), lbc); + if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { + ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), + ISurfaceComposer::MAX_LAYERS); + return NO_MEMORY; + } - if (parent == nullptr && addToCurrentState) { - mCurrentState.layersSortedByZ.add(lbc); - } else if (parent == nullptr) { - lbc->onRemovedFromCurrentState(); - } else if (parent->isRemovedFromCurrentState()) { - parent->addChild(lbc); - lbc->onRemovedFromCurrentState(); - } else { - parent->addChild(lbc); - } + wp<IBinder> initialProducer; + if (gbc != nullptr) { + initialProducer = IInterface::asBinder(gbc); + } + setLayerCreatedState(handle, lbc, parentHandle, parentLayer, initialProducer, addToRoot); - if (gbc != nullptr) { - mGraphicBufferProducerList.insert(IInterface::asBinder(gbc).get()); - LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > - mMaxGraphicBufferProducerListSize, - "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", - mGraphicBufferProducerList.size(), - mMaxGraphicBufferProducerListSize, mNumLayers.load()); - } + // Create a transaction includes the initial parent and producer. + Vector<ComposerState> states; + Vector<DisplayState> displays; - if (const auto display = getDefaultDisplayDeviceLocked()) { - lbc->updateTransformHint(display->getTransformHint()); - } - if (outTransformHint) { - *outTransformHint = lbc->getTransformHint(); - } + ComposerState composerState; + composerState.state.what = layer_state_t::eLayerCreated; + composerState.state.surface = handle; + states.add(composerState); - mLayersAdded = true; + lbc->updateTransformHint(mDefaultDisplayTransformHint); + if (outTransformHint) { + *outTransformHint = mDefaultDisplayTransformHint; } - // attach this layer to the client client->attachLayer(handle, lbc); - return NO_ERROR; + return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr, + InputWindowCommands{}, -1 /* desiredPresentTime */, + true /* isAutoTimestamp */, {}, false /* hasListenerCallbacks */, {}, + 0 /* Undefined transactionId */); } void SurfaceFlinger::removeGraphicBufferProducerAsync(const wp<IBinder>& binder) { @@ -3117,16 +3447,14 @@ uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) { } uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { - return setTransactionFlags(flags, Scheduler::TransactionStart::Normal); + return setTransactionFlags(flags, TransactionSchedule::Late); } -uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, - Scheduler::TransactionStart transactionStart) { +uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule, + const sp<IBinder>& token) { uint32_t old = mTransactionFlags.fetch_or(flags); - mVSyncModulator->setTransactionStart(transactionStart); - if ((old & flags)==0) { // wake the server up - signalTransaction(); - } + modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, token); + if ((old & flags) == 0) signalTransaction(); return old; } @@ -3134,148 +3462,303 @@ void SurfaceFlinger::setTraversalNeeded() { mForceTraversal = true; } -bool SurfaceFlinger::flushTransactionQueues() { +void SurfaceFlinger::flushTransactionQueues() { // 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; - bool flushedATransaction = false; + // Layer handles that have transactions with buffers that are ready to be applied. + std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> bufferLayersReadyToPresent; { 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(); + } - auto it = mTransactionQueues.begin(); - while (it != mTransactionQueues.end()) { - auto& [applyToken, transactionQueue] = *it; + if (transactionQueue.empty()) { + it = mPendingTransactionQueues.erase(it); + mTransactionQueueCV.broadcast(); + } else { + it = std::next(it, 1); + } + } - while (!transactionQueue.empty()) { - const auto& transaction = transactionQueue.front(); - if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime, - transaction.states)) { - setTransactionFlags(eTransactionFlushNeeded); - break; + // 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. + while (!mTransactionQueue.empty()) { + auto& transaction = mTransactionQueue.front(); + bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) != + mPendingTransactionQueues.end(); + if (pendingTransactions || + !transactionIsReadyToBeApplied(transaction.frameTimelineInfo, + transaction.isAutoTimestamp, + transaction.desiredPresentTime, + transaction.originUid, transaction.states, + bufferLayersReadyToPresent)) { + mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); + } else { + transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { + bufferLayersReadyToPresent.insert(state.surface); + }); + transactions.emplace_back(std::move(transaction)); } - transactions.push_back(transaction); - applyTransactionState(transaction.states, transaction.displays, transaction.flags, - mPendingInputWindowCommands, transaction.desiredPresentTime, - transaction.buffer, transaction.postTime, - transaction.privileged, transaction.hasListenerCallbacks, - transaction.listenerCallbacks, /*isMainThread*/ true); - transactionQueue.pop(); - flushedATransaction = true; + mTransactionQueue.pop(); + ATRACE_INT("TransactionQueue", mTransactionQueue.size()); } + } - if (transactionQueue.empty()) { - it = mTransactionQueues.erase(it); - mTransactionCV.broadcast(); - } else { - it = std::next(it, 1); + // 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)); } } } - return flushedATransaction; } bool SurfaceFlinger::transactionFlushNeeded() { - return !mTransactionQueues.empty(); + Mutex::Autolock _l(mQueueLock); + return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty(); } +bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const { + // The amount of time SF can delay a frame if it is considered early based + // on the VsyncModulator::VsyncConfig::appWorkDuration + constexpr static std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms; + + const auto currentVsyncPeriod = mScheduler->getDisplayStatInfo(systemTime()).vsyncPeriod; + const auto earlyLatchVsyncThreshold = currentVsyncPeriod / 2; + + const auto prediction = mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId); + if (!prediction.has_value()) { + return false; + } + + if (std::abs(prediction->presentTime - expectedPresentTime) >= + kEarlyLatchMaxThreshold.count()) { + return false; + } -bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, - const Vector<ComposerState>& states) { + return prediction->presentTime >= expectedPresentTime && + prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold; +} +bool SurfaceFlinger::transactionIsReadyToBeApplied( + 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 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 (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime && + if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime && desiredPresentTime < expectedPresentTime + s2ns(1)) { + ATRACE_NAME("not current"); + return false; + } + + if (!mScheduler->isVsyncValid(expectedPresentTime, originUid)) { + ATRACE_NAME("!isVsyncValid"); + return false; + } + + // 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; } for (const ComposerState& state : states) { const layer_state_t& s = state.state; - if (!(s.what & layer_state_t::eAcquireFenceChanged)) { + 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) { + layer = fromHandleLocked(s.surface).promote(); + } else if (s.hasBufferChanges()) { + ALOGW("Transaction with buffer, but no Layer?"); continue; } - if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) { - return false; + if (!layer) { + continue; + } + + ATRACE_NAME(layer->getName().c_str()); + + 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(); + if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) { + ATRACE_NAME("hasPendingBuffer"); + return false; + } } } return true; } -void SurfaceFlinger::setTransactionState( - const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, - const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, - const std::vector<ListenerCallbacks>& listenerCallbacks) { - ATRACE_CALL(); - - const int64_t postTime = systemTime(); - - bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess(); - - Mutex::Autolock _l(mStateLock); +void SurfaceFlinger::queueTransaction(TransactionState& state) { + Mutex::Autolock _l(mQueueLock); // If its TransactionQueue already has a pending TransactionState or if it is pending - auto itr = mTransactionQueues.find(applyToken); + auto itr = mPendingTransactionQueues.find(state.applyToken); // if this is an animation frame, wait until prior animation frame has // been applied by SF - if (flags & eAnimation) { - while (itr != mTransactionQueues.end()) { - status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); + 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 = mTransactionQueues.find(applyToken); + itr = mPendingTransactionQueues.find(state.applyToken); } } - const bool pendingTransactions = itr != mTransactionQueues.end(); - // Expected present time is computed and cached on invalidate, so it may be stale. - if (!pendingTransactions) { - mExpectedPresentTime = calculateExpectedPresentTime(systemTime()); + // Generate a CountDownLatch pending state if this is a synchronous transaction. + if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) { + state.transactionCommittedSignal = std::make_shared<CountDownLatch>( + (state.inputWindowCommands.syncInputWindows + ? (CountDownLatch::eSyncInputWindows | CountDownLatch::eSyncTransaction) + : CountDownLatch::eSyncTransaction)); } - if (pendingTransactions || !transactionIsReadyToBeApplied(desiredPresentTime, states)) { - mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime, - uncacheBuffer, postTime, privileged, - hasListenerCallbacks, listenerCallbacks); - setTransactionFlags(eTransactionFlushNeeded); - return; - } + mTransactionQueue.emplace(state); + ATRACE_INT("TransactionQueue", mTransactionQueue.size()); - applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime, - uncacheBuffer, postTime, privileged, hasListenerCallbacks, - listenerCallbacks); + const auto schedule = [](uint32_t flags) { + if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd; + if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart; + return TransactionSchedule::Late; + }(state.flags); + + setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken); } -void SurfaceFlinger::applyTransactionState( - const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, - const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged, - bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, - bool isMainThread) { - uint32_t transactionFlags = 0; +void SurfaceFlinger::waitForSynchronousTransaction( + const CountDownLatch& transactionCommittedSignal) { + // 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))) { + ALOGE("setTransactionState timed out!"); + } +} - if (flags & eAnimation) { - // For window updates that are part of an animation we must wait for - // previous animation "frames" to be handled. - while (!isMainThread && mAnimTransactionPending) { - status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); - if (CC_UNLIKELY(err != NO_ERROR)) { - // just in case something goes wrong in SF, return to the - // caller after a few seconds. - ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out " - "waiting for previous animation frame"); - mAnimTransactionPending = false; - break; - } +void SurfaceFlinger::signalSynchronousTransactions(const uint32_t flag) { + for (auto it = mTransactionCommittedSignals.begin(); + it != mTransactionCommittedSignals.end();) { + if ((*it)->countDown(flag)) { + it = mTransactionCommittedSignals.erase(it); + } else { + it++; } } +} + +status_t SurfaceFlinger::setTransactionState( + const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states, + const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, + const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, + bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, + const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) { + ATRACE_CALL(); + + uint32_t permissions = + callingThreadHasUnscopedSurfaceFlingerAccess() ? 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) || + callingThreadHasRotateSurfaceFlingerAccess()) { + permissions |= Permission::ROTATE_SURFACE_FLINGER; + } + + if (!(permissions & Permission::ACCESS_SURFACE_FLINGER) && + (flags & (eEarlyWakeupStart | eEarlyWakeupEnd))) { + ALOGE("Only WindowManager is allowed to use eEarlyWakeup[Start|End] flags"); + flags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd); + } + const int64_t postTime = systemTime(); + + IPCThreadState* ipc = IPCThreadState::self(); + const int originPid = ipc->getCallingPid(); + const int originUid = ipc->getCallingUid(); + TransactionState state{frameTimelineInfo, states, + displays, flags, + applyToken, inputWindowCommands, + desiredPresentTime, isAutoTimestamp, + uncacheBuffer, postTime, + permissions, hasListenerCallbacks, + listenerCallbacks, originPid, + originUid, transactionId}; + + // Check for incoming buffer updates and increment the pending buffer count. + state.traverseStatesWithBuffers([&](const layer_state_t& state) { + mBufferCountTracker.increment(state.surface->localBinder()); + }); + queueTransaction(state); + + // Check the pending state to make sure the transaction is synchronous. + if (state.transactionCommittedSignal) { + waitForSynchronousTransaction(*state.transactionCommittedSignal); + } + + return NO_ERROR; +} + +void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo, + const Vector<ComposerState>& states, + const Vector<DisplayState>& displays, uint32_t flags, + const InputWindowCommands& inputWindowCommands, + const int64_t desiredPresentTime, bool isAutoTimestamp, + const client_cache_t& uncacheBuffer, + const int64_t postTime, uint32_t permissions, + bool hasListenerCallbacks, + const std::vector<ListenerCallbacks>& listenerCallbacks, + int originPid, int originUid, uint64_t transactionId) { + uint32_t transactionFlags = 0; for (const DisplayState& display : displays) { transactionFlags |= setDisplayStateLocked(display); } @@ -3284,38 +3767,43 @@ void SurfaceFlinger::applyTransactionState( // that listeners with SurfaceControls will start registration during setClientStateLocked // below. for (const auto& listener : listenerCallbacks) { - mTransactionCompletedThread.startRegistration(listener); - mTransactionCompletedThread.endRegistration(listener); + mTransactionCallbackInvoker.startRegistration(listener); + mTransactionCallbackInvoker.endRegistration(listener); } std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> listenerCallbacksWithSurfaces; uint32_t clientStateFlags = 0; for (const ComposerState& state : states) { - clientStateFlags |= setClientStateLocked(state, desiredPresentTime, postTime, privileged, - listenerCallbacksWithSurfaces); + clientStateFlags |= + setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp, + postTime, permissions, listenerCallbacksWithSurfaces); if ((flags & eAnimation) && state.state.surface) { if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) { - mScheduler->recordLayerHistory(layer.get(), desiredPresentTime, + mScheduler->recordLayerHistory(layer.get(), + isAutoTimestamp ? 0 : desiredPresentTime, LayerHistory::LayerUpdateType::AnimationTX); } } } for (const auto& listenerCallback : listenerCallbacksWithSurfaces) { - mTransactionCompletedThread.endRegistration(listenerCallback); + mTransactionCallbackInvoker.endRegistration(listenerCallback); } // If the state doesn't require a traversal and there are callbacks, send them now if (!(clientStateFlags & eTraversalNeeded) && hasListenerCallbacks) { - mTransactionCompletedThread.sendCallbacks(); + mTransactionCallbackInvoker.sendCallbacks(); } transactionFlags |= clientStateFlags; - transactionFlags |= addInputWindowCommands(inputWindowCommands); + if (permissions & Permission::ACCESS_SURFACE_FLINGER) { + transactionFlags |= addInputWindowCommands(inputWindowCommands); + } else if (!inputWindowCommands.empty()) { + ALOGE("Only privileged callers are allowed to send input commands."); + } if (uncacheBuffer.isValid()) { ClientCache::getInstance().erase(uncacheBuffer); - getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id); } // If a synchronous transaction is explicitly requested without any changes, force a transaction @@ -3327,86 +3815,25 @@ void SurfaceFlinger::applyTransactionState( transactionFlags = eTransactionNeeded; } - // If we are on the main thread, we are about to preform a traversal. Clear the traversal bit - // so we don't have to wake up again next frame to preform an uneeded traversal. - if (isMainThread && (transactionFlags & eTraversalNeeded)) { - transactionFlags = transactionFlags & (~eTraversalNeeded); - mForceTraversal = true; - } - - const auto transactionStart = [](uint32_t flags) { - if (flags & eEarlyWakeup) { - return Scheduler::TransactionStart::Early; - } - if (flags & eExplicitEarlyWakeupEnd) { - return Scheduler::TransactionStart::EarlyEnd; - } - if (flags & eExplicitEarlyWakeupStart) { - return Scheduler::TransactionStart::EarlyStart; - } - return Scheduler::TransactionStart::Normal; - }(flags); - if (transactionFlags) { if (mInterceptor->isEnabled()) { - mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags); + mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags, + originPid, originUid, transactionId); } - // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag - if (flags & eEarlyWakeup) { - ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]"); + // We are on the main thread, we are about to preform a traversal. Clear the traversal bit + // so we don't have to wake up again next frame to preform an unnecessary traversal. + if (transactionFlags & eTraversalNeeded) { + transactionFlags = transactionFlags & (~eTraversalNeeded); + mForceTraversal = true; } - - if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) { - ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags"); - flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd); + if (transactionFlags) { + setTransactionFlags(transactionFlags); } - // this triggers the transaction - setTransactionFlags(transactionFlags, transactionStart); - if (flags & eAnimation) { mAnimTransactionPending = true; } - - // if this is a synchronous transaction, wait for it to take effect - // before returning. - const bool synchronous = flags & eSynchronous; - const bool syncInput = inputWindowCommands.syncInputWindows; - if (!synchronous && !syncInput) { - return; - } - - if (synchronous) { - mTransactionPending = true; - } - if (syncInput) { - mPendingSyncInputWindows = true; - } - - - // applyTransactionState can be called by either the main SF thread or by - // another process through setTransactionState. While a given process may wish - // to wait on synchronous transactions, the main SF thread should never - // be blocked. Therefore, we only wait if isMainThread is false. - while (!isMainThread && (mTransactionPending || mPendingSyncInputWindows)) { - status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); - if (CC_UNLIKELY(err != NO_ERROR)) { - // just in case something goes wrong in SF, return to the - // called after a few seconds. - ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!"); - mTransactionPending = false; - mPendingSyncInputWindows = false; - break; - } - } - } else { - // even if a transaction is not needed, we need to update VsyncModulator - // about explicit early indications - if (transactionStart == Scheduler::TransactionStart::EarlyStart || - transactionStart == Scheduler::TransactionStart::EarlyEnd) { - mVSyncModulator->setTransactionStart(transactionStart); - } } } @@ -3435,12 +3862,12 @@ uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) { state.orientation = s.orientation; flags |= eDisplayTransactionNeeded; } - if (state.frame != s.frame) { - state.frame = s.frame; + if (state.orientedDisplaySpaceRect != s.orientedDisplaySpaceRect) { + state.orientedDisplaySpaceRect = s.orientedDisplaySpaceRect; flags |= eDisplayTransactionNeeded; } - if (state.viewport != s.viewport) { - state.viewport = s.viewport; + if (state.layerStackSpaceRect != s.layerStackSpaceRect) { + state.layerStackSpaceRect = s.layerStackSpaceRect; flags |= eDisplayTransactionNeeded; } } @@ -3471,43 +3898,61 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermis } uint32_t SurfaceFlinger::setClientStateLocked( - const ComposerState& composerState, int64_t desiredPresentTime, int64_t postTime, - bool privileged, - std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks) { + 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; + std::vector<ListenerCallbacks> filteredListeners; for (auto& listener : s.listeners) { + // Starts a registration but separates the callback ids according to callback type. This + // allows the callback invoker to send on latch callbacks earlier. // note that startRegistration will not re-register if the listener has // already be registered for a prior surface control - mTransactionCompletedThread.startRegistration(listener); - listenerCallbacks.insert(listener); + + 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); + } } + const uint64_t what = s.what; + uint32_t flags = 0; sp<Layer> layer = nullptr; if (s.surface) { - layer = fromHandleLocked(s.surface).promote(); + if (what & layer_state_t::eLayerCreated) { + layer = handleLayerCreatedLocked(s.surface); + if (layer) { + // put the created layer into mLayersByLocalBinderToken. + mLayersByLocalBinderToken.emplace(s.surface->localBinder(), layer); + flags |= eTransactionNeeded | eTraversalNeeded; + mLayersAdded = true; + } + } else { + layer = fromHandleLocked(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"); } if (layer == nullptr) { for (auto& [listener, callbackIds] : s.listeners) { - mTransactionCompletedThread.registerUnpresentedCallbackHandle( + mTransactionCallbackInvoker.registerUnpresentedCallbackHandle( new CallbackHandle(listener, callbackIds, s.surface)); } return 0; } - uint32_t flags = 0; - - const uint64_t what = s.what; - - // If we are deferring transaction, make sure to push the pending state, as otherwise the - // pending state will also be deferred. - if (what & layer_state_t::eDeferTransaction_legacy) { - layer->pushPendingState(); - } - // Only set by BLAST adapter layers if (what & layer_state_t::eProducerDisconnect) { layer->onDisconnect(); @@ -3539,9 +3984,12 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (what & layer_state_t::eRelativeLayerChanged) { // NOTE: index needs to be calculated before we update the state const auto& p = layer->getParent(); + const auto& relativeHandle = s.relativeLayerSurfaceControl ? + s.relativeLayerSurfaceControl->getHandle() : nullptr; if (p == nullptr) { ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); - if (layer->setRelativeLayer(s.relativeLayerHandle, s.z) && idx >= 0) { + if (layer->setRelativeLayer(relativeHandle, s.z) && + idx >= 0) { mCurrentState.layersSortedByZ.removeAt(idx); mCurrentState.layersSortedByZ.add(layer); // we need traversal (state changed) @@ -3549,7 +3997,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTransactionNeeded|eTraversalNeeded; } } else { - if (p->setChildRelativeLayer(layer, s.relativeLayerHandle, s.z)) { + if (p->setChildRelativeLayer(layer, relativeHandle, s.z)) { flags |= eTransactionNeeded|eTraversalNeeded; } } @@ -3586,15 +4034,20 @@ uint32_t SurfaceFlinger::setClientStateLocked( // 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 the WindowManager only uses rotation in one case, which is on a top - // level layer in which cropping is not an issue. + // 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 - // (a.k.a. everyone except WindowManager and tests) from setting non rectangle preserving - // transformations. - if (layer->setMatrix(s.matrix, privileged)) - flags |= eTraversalNeeded; + // 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 (what & layer_state_t::eTransparentRegionChanged) { if (layer->setTransparentRegionHint(s.transparentRegion)) @@ -3604,16 +4057,16 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setFlags(s.flags, s.mask)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eCropChanged_legacy) { - if (layer->setCrop_legacy(s.crop_legacy)) flags |= eTraversalNeeded; - } if (what & layer_state_t::eCornerRadiusChanged) { if (layer->setCornerRadius(s.cornerRadius)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur) { + if (what & layer_state_t::eBackgroundBlurRadiusChanged && mSupportsBlur) { if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded; } + if (what & layer_state_t::eBlurRegionsChanged) { + if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded; + } if (what & layer_state_t::eLayerStackChanged) { ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); // We only allow setting layer stacks for top level layers, @@ -3634,36 +4087,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTransactionNeeded | eTraversalNeeded | eTransformHintUpdateNeeded; } } - if (what & layer_state_t::eDeferTransaction_legacy) { - if (s.barrierHandle_legacy != nullptr) { - layer->deferTransactionUntil_legacy(s.barrierHandle_legacy, s.frameNumber_legacy); - } else if (s.barrierGbp_legacy != nullptr) { - const sp<IGraphicBufferProducer>& gbp = s.barrierGbp_legacy; - if (authenticateSurfaceTextureLocked(gbp)) { - const auto& otherLayer = - (static_cast<MonitoredProducer*>(gbp.get()))->getLayer(); - layer->deferTransactionUntil_legacy(otherLayer, s.frameNumber_legacy); - } else { - ALOGE("Attempt to defer transaction to to an" - " unrecognized GraphicBufferProducer"); - } - } - // We don't trigger a traversal here because if no other state is - // changed, we don't want this to cause any more work - } - if (what & layer_state_t::eReparentChildren) { - if (layer->reparentChildren(s.reparentHandle)) { - flags |= eTransactionNeeded|eTraversalNeeded; - } - } - if (what & layer_state_t::eDetachChildren) { - layer->detachChildren(); - } - if (what & layer_state_t::eOverrideScalingModeChanged) { - layer->setOverrideScalingMode(s.overrideScalingMode); - // We don't trigger a traversal here because if no other state is - // changed, we don't want this to cause any more work - } if (what & layer_state_t::eTransformChanged) { if (layer->setTransform(s.transform)) flags |= eTraversalNeeded; } @@ -3674,9 +4097,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (what & layer_state_t::eCropChanged) { if (layer->setCrop(s.crop)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eFrameChanged) { - if (layer->setFrame(s.frame)) flags |= eTraversalNeeded; - } if (what & layer_state_t::eAcquireFenceChanged) { if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded; } @@ -3697,13 +4117,22 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::eInputInfoChanged) { if (privileged) { - layer->setInputInfo(s.inputInfo); + layer->setInputInfo(*s.inputHandle->getInfo()); flags |= eTraversalNeeded; } else { ALOGE("Attempt to update InputWindowInfo without permission ACCESS_SURFACE_FLINGER"); } } + 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) { + // 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); + } if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded; } if (what & layer_state_t::eColorSpaceAgnosticChanged) { @@ -3720,12 +4149,16 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } if (what & layer_state_t::eFrameRateChanged) { - if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility, - "SurfaceFlinger::setClientStateLocked") && - layer->setFrameRate(Layer::FrameRate(s.frameRate, - Layer::FrameRate::convertCompatibility( - s.frameRateCompatibility)))) { - flags |= eTraversalNeeded; + 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); + + if (layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), compatibility, strategy))) { + flags |= eTraversalNeeded; + } } } if (what & layer_state_t::eFixedTransformHintChanged) { @@ -3733,51 +4166,84 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded | eTransformHintUpdateNeeded; } } + if (what & layer_state_t::eAutoRefreshChanged) { + layer->setAutoRefresh(s.autoRefresh); + } + 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 (what & layer_state_t::eStretchChanged) { + if (layer->setStretchEffect(s.stretchEffect)) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eBufferCropChanged) { + if (layer->setBufferCrop(s.bufferCrop)) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eDestinationFrameChanged) { + if (layer->setDestinationFrame(s.destinationFrame)) { + flags |= eTraversalNeeded; + } + } // This has to happen after we reparent children because when we reparent to null we remove // child layers from current state and remove its relative z. If the children are reparented in // the same transaction, then we have to make sure we reparent the children first so we do not // lose its relative z order. if (what & layer_state_t::eReparent) { bool hadParent = layer->hasParent(); - if (layer->reparent(s.parentHandleForChild)) { + auto parentHandle = (s.parentSurfaceControlForChild) + ? s.parentSurfaceControlForChild->getHandle() + : nullptr; + if (layer->reparent(parentHandle)) { if (!hadParent) { + layer->setIsAtRoot(false); mCurrentState.layersSortedByZ.remove(layer); } flags |= eTransactionNeeded | eTraversalNeeded; } } std::vector<sp<CallbackHandle>> callbackHandles; - if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!s.listeners.empty())) { - for (auto& [listener, callbackIds] : s.listeners) { + if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { + for (auto& [listener, callbackIds] : filteredListeners) { callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); } } bool bufferChanged = what & layer_state_t::eBufferChanged; bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged; - sp<GraphicBuffer> buffer; + std::shared_ptr<renderengine::ExternalTexture> buffer; if (bufferChanged && cacheIdChanged && s.buffer != nullptr) { - buffer = s.buffer; - bool success = ClientCache::getInstance().add(s.cachedBuffer, s.buffer); - if (success) { - getRenderEngine().cacheExternalTextureBuffer(s.buffer); - success = ClientCache::getInstance() - .registerErasedRecipient(s.cachedBuffer, - wp<ClientCache::ErasedRecipient>(this)); - if (!success) { - getRenderEngine().unbindExternalTextureBuffer(s.buffer->getId()); - } - } + 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) { - buffer = s.buffer; + } else if (bufferChanged && s.buffer != nullptr) { + buffer = std::make_shared< + renderengine::ExternalTexture>(s.buffer, getRenderEngine(), + renderengine::ExternalTexture::Usage::READABLE); } if (buffer) { - if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, - s.cachedBuffer)) { + 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)) { flags |= eTraversalNeeded; } + } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { + layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime); } + if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; // Do not put anything that updates layer state or modifies flags after // setTransactionCompletedListener @@ -3785,17 +4251,12 @@ uint32_t SurfaceFlinger::setClientStateLocked( } uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) { - uint32_t flags = 0; - if (inputWindowCommands.syncInputWindows) { - flags |= eTraversalNeeded; - } - - mPendingInputWindowCommands.merge(inputWindowCommands); - return flags; + bool hasChanges = mInputWindowCommands.merge(inputWindowCommands); + return hasChanges ? eTraversalNeeded : 0; } status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle, - sp<IBinder>* outHandle) { + sp<IBinder>* outHandle, int32_t* outLayerId) { if (!mirrorFromHandle) { return NAME_NOT_FOUND; } @@ -3817,9 +4278,10 @@ status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder> return result; } - mirrorLayer->mClonedChild = mirrorFrom->createClone(); + mirrorLayer->setClonedChild(mirrorFrom->createClone()); } + *outLayerId = mirrorLayer->sequence; return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false, nullptr /* outTransformHint */); } @@ -3828,8 +4290,8 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& clie uint32_t h, PixelFormat format, uint32_t flags, LayerMetadata metadata, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, - const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer, - uint32_t* outTransformHint) { + 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)); @@ -3846,28 +4308,18 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& clie std::string uniqueName = getUniqueLayerName(name.string()); - bool primaryDisplayOnly = false; - - // window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java - // TODO b/64227542 - if (metadata.has(METADATA_WINDOW_TYPE)) { - int32_t windowType = metadata.getInt32(METADATA_WINDOW_TYPE, 0); - if (windowType == 441731) { - metadata.setInt32(METADATA_WINDOW_TYPE, InputWindowInfo::TYPE_NAVIGATION_BAR_PANEL); - primaryDisplayOnly = true; - } - } - switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: - result = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags, - std::move(metadata), format, handle, gbp, &layer); - - break; - case ISurfaceComposerClient::eFXSurfaceBufferState: + case ISurfaceComposerClient::eFXSurfaceBufferState: { result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags, std::move(metadata), handle, &layer); - break; + std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter(); + if (pendingBufferCounter) { + std::string counterName = layer->getPendingBufferCounterName(); + mBufferCountTracker.add((*handle)->localBinder(), counterName, + pendingBufferCounter); + } + } break; case ISurfaceComposerClient::eFXSurfaceEffect: // check if buffer size is set for color layer. if (w > 0 || h > 0) { @@ -3898,19 +4350,16 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& clie return result; } - if (primaryDisplayOnly) { - layer->setPrimaryDisplayOnly(); - } - - bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess(); - result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer, - addToCurrentState, outTransformHint); + bool addToRoot = callingThreadHasUnscopedSurfaceFlingerAccess(); + result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer, addToRoot, + outTransformHint); if (result != NO_ERROR) { return result; } mInterceptor->saveSurfaceCreation(layer); setTransactionFlags(eTransactionNeeded); + *outLayerId = layer->sequence; return result; } @@ -4016,14 +4465,14 @@ void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) { setTransactionFlags(eTransactionNeeded); } -void SurfaceFlinger::onHandleDestroyed(sp<Layer>& layer) -{ +void SurfaceFlinger::onHandleDestroyed(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->getParent() == nullptr) { + if (layer->isAtRoot()) { + layer->setIsAtRoot(false); mCurrentState.layersSortedByZ.remove(layer); } markLayerPendingRemovalLocked(layer); @@ -4031,6 +4480,7 @@ void SurfaceFlinger::onHandleDestroyed(sp<Layer>& layer) auto it = mLayersByLocalBinderToken.begin(); while (it != mLayersByLocalBinderToken.end()) { if (it->second == layer) { + mBufferCountTracker.remove(it->first->localBinder()); it = mLayersByLocalBinderToken.erase(it); } else { it++; @@ -4058,18 +4508,22 @@ void SurfaceFlinger::onInitializeDisplays() { d.token = token; d.layerStack = 0; d.orientation = ui::ROTATION_0; - d.frame.makeInvalid(); - d.viewport.makeInvalid(); + d.orientedDisplaySpaceRect.makeInvalid(); + d.layerStackSpaceRect.makeInvalid(); d.width = 0; d.height = 0; displays.add(d); - setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, false, - {}); + + nsecs_t now = systemTime(); + // 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 */); setPowerModeInternal(display, hal::PowerMode::ON); const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod); - + mDefaultDisplayTransformHint = display->getTransformHint(); // Use phase of 0 since phase is not known. // Use latency of 0, which will snap to the ideal latency. DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod}; @@ -4087,10 +4541,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: return; } - const auto displayId = display->getId(); - LOG_ALWAYS_FATAL_IF(!displayId); - - ALOGD("Setting power mode %d on display %s", mode, to_string(*displayId).c_str()); + const auto displayId = display->getPhysicalId(); + ALOGD("Setting power mode %d on display %s", mode, to_string(displayId).c_str()); const hal::PowerMode currentMode = display->getPowerMode(); if (mode == currentMode) { @@ -4104,12 +4556,17 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); if (currentMode == hal::PowerMode::OFF) { + // Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315. + // We can merge the syscall later. + if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) { + ALOGW("Couldn't set uclamp.min on display on: %s\n", strerror(errno)); + } if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) { ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno)); } - getHwComposer().setPowerMode(*displayId, mode); + getHwComposer().setPowerMode(displayId, mode); if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) { - getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState); + getHwComposer().setVsyncEnabled(displayId, mHWCVsyncPendingState); mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, vsyncPeriod); } @@ -4122,20 +4579,23 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) { ALOGW("Couldn't set SCHED_OTHER on display off: %s\n", strerror(errno)); } + if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) { + ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno)); + } if (display->isPrimary() && currentMode != hal::PowerMode::DOZE_SUSPEND) { mScheduler->disableHardwareVsync(true); mScheduler->onScreenReleased(mAppConnectionHandle); } // Make sure HWVsync is disabled before turning off the display - getHwComposer().setVsyncEnabled(*displayId, hal::Vsync::DISABLE); + getHwComposer().setVsyncEnabled(displayId, hal::Vsync::DISABLE); - getHwComposer().setPowerMode(*displayId, mode); + getHwComposer().setPowerMode(displayId, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display } else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) { // Update display while dozing - getHwComposer().setPowerMode(*displayId, mode); + getHwComposer().setPowerMode(displayId, mode); if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) { mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, vsyncPeriod); @@ -4146,10 +4606,10 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mScheduler->disableHardwareVsync(true); mScheduler->onScreenReleased(mAppConnectionHandle); } - getHwComposer().setPowerMode(*displayId, mode); + getHwComposer().setPowerMode(displayId, mode); } else { ALOGE("Attempting to set unknown power mode: %d\n", mode); - getHwComposer().setPowerMode(*displayId, mode); + getHwComposer().setPowerMode(displayId, mode); } if (display->isPrimary()) { @@ -4158,7 +4618,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON); } - ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str()); + ALOGD("Finished setting power mode %d on display %s", mode, to_string(displayId).c_str()); } void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) { @@ -4189,17 +4649,18 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } else { static const std::unordered_map<std::string, Dumper> dumpers = { {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)}, - {"--dispsync"s, - dumper([this](std::string& s) { mScheduler->getPrimaryDispSync().dump(s); })}, + {"--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)}, + {"--planner"s, argsDumper(&SurfaceFlinger::dumpPlannerInfo)}, {"--static-screen"s, dumper(&SurfaceFlinger::dumpStaticScreenStats)}, {"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)}, {"--vsync"s, dumper(&SurfaceFlinger::dumpVSync)}, {"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)}, + {"--frametimeline"s, argsDumper(&SurfaceFlinger::dumpFrameTimeline)}, }; const auto flag = args.empty() ? ""s : std::string(String8(args[0])); @@ -4239,7 +4700,7 @@ 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.writeToFileAsync(); + mTracing.writeToFile(); } return doDump(fd, DumpArgs(), asProto); @@ -4282,6 +4743,10 @@ void SurfaceFlinger::dumpTimeStats(const DumpArgs& args, bool asProto, std::stri mTimeStats->parseArgs(asProto, args, result); } +void SurfaceFlinger::dumpFrameTimeline(const DumpArgs& args, std::string& result) const { + 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() { @@ -4295,12 +4760,10 @@ void SurfaceFlinger::logFrameStats() { void SurfaceFlinger::appendSfConfigString(std::string& result) const { result.append(" [sf"); - if (isLayerTripleBufferingDisabled()) - result.append(" DISABLE_TRIPLE_BUFFERING"); - StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset); StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv); - StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize); + StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%zu", + getHwComposer().getMaxVirtualDisplayDimension()); StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework); StringAppendF(&result, " NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64, maxFrameBufferAcquiredBuffers); @@ -4313,31 +4776,25 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { mRefreshRateStats->dump(result); result.append("\n"); - mPhaseConfiguration->dump(result); + mVsyncConfiguration->dump(result); StringAppendF(&result, " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n", dispSyncPresentTimeOffset, getVsyncPeriodFromHWC()); - scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy(); - StringAppendF(&result, - "DesiredDisplayConfigSpecs (DisplayManager): default config ID: %d" - ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n", - policy.defaultConfig.value(), policy.primaryRange.min, policy.primaryRange.max, - policy.appRequestRange.min, policy.appRequestRange.max); - StringAppendF(&result, "(config override by backdoor: %s)\n\n", - mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); - scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy(); - if (currentPolicy != policy) { - StringAppendF(&result, - "DesiredDisplayConfigSpecs (Override): default config ID: %d" - ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n", - currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min, - currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min, - currentPolicy.appRequestRange.max); - } + mRefreshRateConfigs->dump(result); + + StringAppendF(&result, "(mode override by backdoor: %s)\n\n", + mDebugDisplayModeSetByBackdoor ? "yes" : "no"); mScheduler->dump(mAppConnectionHandle, result); - mScheduler->getPrimaryDispSync().dump(result); + mScheduler->dumpVsync(result); +} + +void SurfaceFlinger::dumpPlannerInfo(const DumpArgs& args, std::string& result) const { + for (const auto& [token, display] : mDisplays) { + const auto compositionDisplay = display->getCompositionDisplay(); + compositionDisplay->dumpPlannerInfo(args, result); + } } void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const { @@ -4414,7 +4871,7 @@ void SurfaceFlinger::dumpBufferingStats(std::string& result) const { void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { for (const auto& [token, display] : mDisplays) { - const auto displayId = display->getId(); + const auto displayId = PhysicalDisplayId::tryCast(display->getId()); if (!displayId) { continue; } @@ -4471,7 +4928,7 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { // TODO: print out if wide-color mode is active or not for (const auto& [token, display] : mDisplays) { - const auto displayId = display->getId(); + const auto displayId = PhysicalDisplayId::tryCast(display->getId()); if (!displayId) { continue; } @@ -4560,8 +5017,6 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co result.append("Build configuration:"); colorizer.reset(result); appendSfConfigString(result); - appendUiConfigString(result); - appendGuiConfigString(result); result.append("\n"); result.append("\nDisplay identification data:\n"); @@ -4604,7 +5059,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co StringAppendF(&result, "Composition layers\n"); mDrawingState.traverseInZOrder([&](Layer* layer) { auto* compositionState = layer->getCompositionState(); - if (!compositionState) return; + if (!compositionState || !compositionState->isVisible) return; android::base::StringAppendF(&result, "* Layer %p (%s)\n", layer, layer->getDebugName() ? layer->getDebugName() @@ -4641,6 +5096,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co getRenderEngine().dump(result); + result.append("ClientCache state:\n"); + ClientCache::getInstance().dump(result); DebugEGLImageTracker::getInstance()->dump(result); if (const auto display = getDefaultDisplayDeviceLocked()) { @@ -4654,15 +5111,22 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co " gpu_to_cpu_unsupported : %d\n", mTransactionFlags.load(), !mGpuToCpuSupported); - if (const auto displayId = getInternalDisplayIdLocked(); - displayId && getHwComposer().isConnected(*displayId)) { - const auto activeConfig = getHwComposer().getActiveConfig(*displayId); + if (const auto display = getDefaultDisplayDeviceLocked()) { + 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()); + } else { + fps = "unknown"; + xDpi = "unknown"; + yDpi = "unknown"; + } StringAppendF(&result, - " refresh-rate : %f fps\n" - " x-dpi : %f\n" - " y-dpi : %f\n", - 1e9 / getHwComposer().getDisplayVsyncPeriod(*displayId), - activeConfig->getDpiX(), activeConfig->getDpiY()); + " refresh-rate : %s\n" + " x-dpi : %s\n" + " y-dpi : %s\n", + fps.c_str(), xDpi.c_str(), yDpi.c_str()); } StringAppendF(&result, " transaction time: %f us\n", inTransactionDuration / 1000.0); @@ -4677,7 +5141,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co * HWC layer minidump */ for (const auto& [token, display] : mDisplays) { - const auto displayId = display->getId(); + const auto displayId = HalDisplayId::tryCast(display->getId()); if (!displayId) { continue; } @@ -4690,6 +5154,13 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co result.append("\n"); } + { + DumpArgs plannerArgs; + plannerArgs.add(); // first argument is ignored + plannerArgs.add(String16("--layers")); + dumpPlannerInfo(plannerArgs, result); + } + /* * Dump HWComposer state */ @@ -4710,23 +5181,24 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co result.append("\n"); } -void SurfaceFlinger::updateColorMatrixLocked() { - mat4 colorMatrix; - if (mGlobalSaturationFactor != 1.0f) { - // Rec.709 luma coefficients - float3 luminance{0.213f, 0.715f, 0.072f}; - luminance *= 1.0f - mGlobalSaturationFactor; - mat4 saturationMatrix = mat4( - vec4{luminance.r + mGlobalSaturationFactor, luminance.r, luminance.r, 0.0f}, - vec4{luminance.g, luminance.g + mGlobalSaturationFactor, luminance.g, 0.0f}, - vec4{luminance.b, luminance.b, luminance.b + mGlobalSaturationFactor, 0.0f}, - vec4{0.0f, 0.0f, 0.0f, 1.0f} - ); - colorMatrix = mClientColorMatrix * saturationMatrix * mDaltonizer(); - } else { - colorMatrix = mClientColorMatrix * mDaltonizer(); +mat4 SurfaceFlinger::calculateColorMatrix(float saturation) { + if (saturation == 1) { + return mat4(); } + float3 luminance{0.213f, 0.715f, 0.072f}; + luminance *= 1.0f - saturation; + mat4 saturationMatrix = mat4(vec4{luminance.r + saturation, luminance.r, luminance.r, 0.0f}, + vec4{luminance.g, luminance.g + saturation, luminance.g, 0.0f}, + vec4{luminance.b, luminance.b, luminance.b + saturation, 0.0f}, + vec4{0.0f, 0.0f, 0.0f, 1.0f}); + return saturationMatrix; +} + +void SurfaceFlinger::updateColorMatrixLocked() { + mat4 colorMatrix = + mClientColorMatrix * calculateColorMatrix(mGlobalSaturationFactor) * mDaltonizer(); + if (mCurrentState.colorMatrix != colorMatrix) { mCurrentState.colorMatrix = colorMatrix; mCurrentState.colorMatrixChanged = true; @@ -4738,33 +5210,40 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { #pragma clang diagnostic push #pragma clang diagnostic error "-Wswitch-enum" switch (static_cast<ISurfaceComposerTag>(code)) { + case ENABLE_VSYNC_INJECTIONS: + case INJECT_VSYNC: + if (!hasMockHwc()) return PERMISSION_DENIED; + [[fallthrough]]; // These methods should at minimum make sure that the client requested // access to SF. case BOOT_FINISHED: case CLEAR_ANIMATION_FRAME_STATS: case CREATE_DISPLAY: case DESTROY_DISPLAY: - case ENABLE_VSYNC_INJECTIONS: case GET_ANIMATION_FRAME_STATS: + case OVERRIDE_HDR_TYPES: case GET_HDR_CAPABILITIES: - case SET_DESIRED_DISPLAY_CONFIG_SPECS: - case GET_DESIRED_DISPLAY_CONFIG_SPECS: + case SET_DESIRED_DISPLAY_MODE_SPECS: + case GET_DESIRED_DISPLAY_MODE_SPECS: case SET_ACTIVE_COLOR_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 INJECT_VSYNC: case SET_POWER_MODE: case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: case GET_DISPLAYED_CONTENT_SAMPLE: - case NOTIFY_POWER_HINT: + case ADD_TUNNEL_MODE_ENABLED_LISTENER: + case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: + case NOTIFY_POWER_BOOST: case SET_GLOBAL_SHADOW_SETTINGS: case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { - // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN is 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; + // 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; if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", @@ -4790,13 +5269,14 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // information, so it is OK to pass them. case AUTHENTICATE_SURFACE: case GET_ACTIVE_COLOR_MODE: - case GET_ACTIVE_CONFIG: + 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_DISPLAY_INFO: - case GET_DISPLAY_CONFIGS: + 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: @@ -4812,11 +5292,30 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // special permissions. case SET_FRAME_RATE: case GET_DISPLAY_BRIGHTNESS_SUPPORT: - case SET_DISPLAY_BRIGHTNESS: { + // captureLayers and captureDisplay will handle the permission check in the function + case CAPTURE_LAYERS: + case CAPTURE_DISPLAY: + 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 CAPTURE_LAYERS: - case CAPTURE_SCREEN: + 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: case REMOVE_REGION_SAMPLING_LISTENER: { // codes that require permission check @@ -4830,7 +5329,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return OK; } - case CAPTURE_SCREEN_BY_ID: { + case ADD_TRANSACTION_TRACE_LISTENER: + case CAPTURE_DISPLAY_BY_ID: { IPCThreadState* ipc = IPCThreadState::self(); const int uid = ipc->getCallingUid(); if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { @@ -4838,6 +5338,13 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return PERMISSION_DENIED; } + case ON_PULL_ATOM: { + const int uid = IPCThreadState::self()->getCallingUid(); + if (uid == AID_SYSTEM) { + return OK; + } + return PERMISSION_DENIED; + } } // These codes are used for the IBinder protocol to either interrogate the recipient @@ -4848,9 +5355,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { code == IBinder::SYSPROPS_TRANSACTION) { return OK; } - // Numbers from 1000 to 1036 are currently used for backdoors. The code + // Numbers from 1000 to 1040 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 <= 1036) { + if (code >= 1000 && code <= 1040) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -4993,14 +5500,14 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r mForceFullDamage = n != 0; return NO_ERROR; } - case 1018: { // Modify Choreographer's phase offset + case 1018: { // Modify Choreographer's duration n = data.readInt32(); - mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast<nsecs_t>(n)); + mScheduler->setDuration(mAppConnectionHandle, std::chrono::nanoseconds(n), 0ns); return NO_ERROR; } - case 1019: { // Modify SurfaceFlinger's phase offset + case 1019: { // Modify SurfaceFlinger's duration n = data.readInt32(); - mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast<nsecs_t>(n)); + mScheduler->setDuration(mSfConnectionHandle, std::chrono::nanoseconds(n), 0ns); return NO_ERROR; } case 1020: { // Layer updates interceptor @@ -5016,8 +5523,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1021: { // Disable HWC virtual displays - n = data.readInt32(); - mUseHwcVirtualDisplays = !n; + const bool enable = data.readInt32() != 0; + static_cast<void>(schedule([this, enable] { enableHalVirtualDisplays(enable); })); return NO_ERROR; } case 1022: { // Set saturation boost @@ -5044,19 +5551,19 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } case 1025: { // Set layer tracing n = data.readInt32(); + bool tracingEnabledChanged; if (n) { ALOGD("LayerTracing enabled"); - mTracingEnabledChanged = mTracing.enable(); - reply->writeInt32(NO_ERROR); + tracingEnabledChanged = mTracing.enable(); + if (tracingEnabledChanged) { + schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait(); + } } else { ALOGD("LayerTracing disabled"); - mTracingEnabledChanged = mTracing.disable(); - if (mTracingEnabledChanged) { - reply->writeInt32(mTracing.writeToFile()); - } else { - reply->writeInt32(NO_ERROR); - } + tracingEnabledChanged = mTracing.disable(); } + mTracingEnabledChanged = tracingEnabledChanged; + reply->writeInt32(NO_ERROR); return NO_ERROR; } case 1026: { // Get layer tracing status @@ -5164,16 +5671,37 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1035: { - n = data.readInt32(); - mDebugDisplayConfigSetByBackdoor = false; - if (n >= 0) { - const auto displayToken = getInternalDisplayToken(); - status_t result = setActiveConfig(displayToken, n); - if (result != NO_ERROR) { - return result; + 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; + } + + return std::make_optional<PhysicalDisplayId>(inputDisplayId); } - mDebugDisplayConfigSetByBackdoor = true; + + return getInternalDisplayId(); + }(); + + 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; } case 1036: { @@ -5188,6 +5716,83 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } 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); + return NO_ERROR; + } + // Modify the max number of display frames stored within FrameTimeline + case 1038: { + n = data.readInt32(); + if (n < 0 || n > MAX_ALLOWED_DISPLAY_FRAMES) { + ALOGW("Invalid max size. Maximum allowed is %d", MAX_ALLOWED_DISPLAY_FRAMES); + return BAD_VALUE; + } + if (n == 0) { + // restore to default + mFrameTimeline->reset(); + return NO_ERROR; + } + mFrameTimeline->setMaxDisplayFrames(n); + return NO_ERROR; + } + case 1039: { + PhysicalDisplayId displayId = [&]() { + Mutex::Autolock lock(mStateLock); + return getDefaultDisplayDeviceLocked()->getPhysicalId(); + }(); + + auto inUid = static_cast<uid_t>(data.readInt32()); + const auto refreshRate = data.readFloat(); + mScheduler->setPreferredRefreshRateForUid(FrameRateOverride{inUid, refreshRate}); + mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId); + return NO_ERROR; + } + // Toggle caching feature + // First argument is an int32 - nonzero enables caching and zero disables caching + // 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); + } + } + } + return OK; + }).get(); + + if (error != OK) { + return error; + } + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + } } } return err; @@ -5213,17 +5818,16 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { // Update the overlay on the main thread to avoid race conditions with // mRefreshRateConfigs->getCurrentRefreshRate() static_cast<void>(schedule([=] { - const auto desiredActiveConfig = getDesiredActiveConfig(); - const auto& current = desiredActiveConfig - ? mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig->configId) - : mRefreshRateConfigs->getCurrentRefreshRate(); - const auto& min = mRefreshRateConfigs->getMinRefreshRate(); - - if (current != min) { - const bool timerExpired = mKernelIdleTimerEnabled && expired; - + const auto desiredActiveMode = getDesiredActiveMode(); + const std::optional<DisplayModeId> desiredModeId = + desiredActiveMode ? std::make_optional(desiredActiveMode->modeId) : std::nullopt; + + const bool timerExpired = mKernelIdleTimerEnabled && expired; + const auto newRefreshRate = + mRefreshRateConfigs->onKernelTimerChanged(desiredModeId, timerExpired); + if (newRefreshRate) { if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) { - mRefreshRateOverlay->changeRefreshRate(timerExpired ? min : current); + mRefreshRateOverlay->changeRefreshRate(*newRefreshRate); } mEventQueue->invalidate(); } @@ -5254,8 +5858,6 @@ void SurfaceFlinger::toggleKernelIdleTimer() { mKernelIdleTimerEnabled = true; } break; - case KernelIdleTimerAction::NoChange: - break; } } @@ -5272,45 +5874,6 @@ private: const int mApi; }; -status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken, - sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers, - Dataspace reqDataspace, ui::PixelFormat reqPixelFormat, - const Rect& sourceCrop, uint32_t reqWidth, - uint32_t reqHeight, bool useIdentityTransform, - ui::Rotation rotation, bool captureSecureLayers) { - ATRACE_CALL(); - - if (!displayToken) return BAD_VALUE; - - auto renderAreaRotation = ui::Transform::toRotationFlags(rotation); - if (renderAreaRotation == ui::Transform::ROT_INVALID) { - ALOGE("%s: Invalid rotation: %s", __FUNCTION__, toCString(rotation)); - renderAreaRotation = ui::Transform::ROT_0; - } - - sp<DisplayDevice> display; - { - Mutex::Autolock lock(mStateLock); - - display = getDisplayDeviceLocked(displayToken); - if (!display) return NAME_NOT_FOUND; - - // set the requested width/height to the logical display viewport size - // by default - if (reqWidth == 0 || reqHeight == 0) { - reqWidth = uint32_t(display->getViewport().width()); - reqHeight = uint32_t(display->getViewport().height()); - } - } - - DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace, - renderAreaRotation, captureSecureLayers); - auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display, - std::placeholders::_1); - return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, - useIdentityTransform, outCapturedSecureLayers); -} - static Dataspace pickDataspaceFromColorMode(const ColorMode colorMode) { switch (colorMode) { case ColorMode::DISPLAY_P3: @@ -5323,6 +5886,32 @@ static Dataspace pickDataspaceFromColorMode(const ColorMode colorMode) { } } +static bool hasCaptureBlackoutContentPermission() { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + return uid == AID_GRAPHICS || uid == AID_SYSTEM || + PermissionCache::checkPermission(sCaptureBlackoutContent, pid, uid); +} + +static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if (uid == AID_GRAPHICS || PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + return OK; + } + + // If the caller doesn't have the correct permissions but is only attempting to screenshot + // itself, we allow it to continue. + if (captureArgs.uid == uid) { + return OK; + } + + ALOGE("Permission Denial: can't take screenshot pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; +} + status_t SurfaceFlinger::setSchedFifo(bool enabled) { static constexpr int kFifoPriority = 2; static constexpr int kOtherPriority = 0; @@ -5340,208 +5929,197 @@ status_t SurfaceFlinger::setSchedFifo(bool enabled) { if (sched_setscheduler(0, sched_policy, ¶m) != 0) { return -errno; } + return NO_ERROR; } -sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) { - const sp<IBinder> displayToken = getPhysicalDisplayTokenLocked(DisplayId{displayOrLayerStack}); - if (displayToken) { - return getDisplayDeviceLocked(displayToken); +status_t SurfaceFlinger::setSchedAttr(bool enabled) { + static const unsigned int kUclampMin = + base::GetUintProperty<unsigned int>("ro.surface_flinger.uclamp.min", 0U); + + if (!kUclampMin) { + // uclamp.min set to 0 (default), skip setting + return NO_ERROR; } - // Couldn't find display by displayId. Try to get display by layerStack since virtual displays - // may not have a displayId. - return getDisplayByLayerStack(displayOrLayerStack); -} -sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) { - for (const auto& [token, display] : mDisplays) { - if (display->getLayerStack() == layerStack) { - return display; - } + // Currently, there is no wrapper in bionic: b/183240349. + struct sched_attr { + uint32_t size; + uint32_t sched_policy; + uint64_t sched_flags; + int32_t sched_nice; + uint32_t sched_priority; + uint64_t sched_runtime; + uint64_t sched_deadline; + uint64_t sched_period; + uint32_t sched_util_min; + uint32_t sched_util_max; + }; + + sched_attr attr = {}; + attr.size = sizeof(attr); + + attr.sched_flags = (SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP); + attr.sched_util_min = enabled ? kUclampMin : 0; + attr.sched_util_max = 1024; + + if (syscall(__NR_sched_setattr, 0, &attr, 0)) { + return -errno; } - return nullptr; -} -status_t SurfaceFlinger::captureScreen(uint64_t displayOrLayerStack, Dataspace* outDataspace, - sp<GraphicBuffer>* outBuffer) { - sp<DisplayDevice> display; - uint32_t width; - uint32_t height; - ui::Transform::RotationFlags captureOrientation; - { - Mutex::Autolock lock(mStateLock); - display = getDisplayByIdOrLayerStack(displayOrLayerStack); - if (!display) { - return NAME_NOT_FOUND; - } + return NO_ERROR; +} - width = uint32_t(display->getViewport().width()); - height = uint32_t(display->getViewport().height()); +status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, + const sp<IScreenCaptureListener>& captureListener) { + ATRACE_CALL(); - const auto orientation = display->getOrientation(); - captureOrientation = ui::Transform::toRotationFlags(orientation); + status_t validate = validateScreenshotPermissions(args); + if (validate != OK) { + return validate; + } - switch (captureOrientation) { - case ui::Transform::ROT_90: - captureOrientation = ui::Transform::ROT_270; - break; + if (!args.displayToken) return BAD_VALUE; - case ui::Transform::ROT_270: - captureOrientation = ui::Transform::ROT_90; - break; + wp<const DisplayDevice> displayWeak; + ui::LayerStack layerStack; + ui::Size reqSize(args.width, args.height); + ui::Dataspace dataspace; + { + Mutex::Autolock lock(mStateLock); + sp<DisplayDevice> display = getDisplayDeviceLocked(args.displayToken); + if (!display) return NAME_NOT_FOUND; + displayWeak = display; + layerStack = display->getLayerStack(); - case ui::Transform::ROT_INVALID: - ALOGE("%s: Invalid orientation: %s", __FUNCTION__, toCString(orientation)); - captureOrientation = ui::Transform::ROT_0; - break; + // set the requested width/height to the logical display layer stack rect size by default + if (args.width == 0 || args.height == 0) { + reqSize = display->getLayerStackSpaceRect().getSize(); + } - default: - break; + // The dataspace is depended on the color mode of display, that could use non-native mode + // (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes, + // 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) { + const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode; + dataspace = pickDataspaceFromColorMode(colorMode); } - *outDataspace = - pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode); } - DisplayRenderArea renderArea(display, Rect(), width, height, *outDataspace, captureOrientation, - false /* captureSecureLayers */); + RenderAreaFuture renderAreaFuture = ftl::defer([=] { + return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize, dataspace, + args.useIdentityTransform, args.captureSecureLayers); + }); + + auto traverseLayers = [this, args, layerStack](const LayerVector::Visitor& visitor) { + traverseLayersInLayerStack(layerStack, args.uid, visitor); + }; - auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display, - std::placeholders::_1); - bool ignored = false; - return captureScreenCommon(renderArea, traverseLayers, outBuffer, ui::PixelFormat::RGBA_8888, - false /* useIdentityTransform */, - ignored /* outCapturedSecureLayers */); + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, args.allowProtected, args.grayscale, + captureListener); } -status_t SurfaceFlinger::captureLayers( - const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer, - const Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, - const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& excludeHandles, - float frameScale, bool childrenOnly) { - ATRACE_CALL(); +status_t SurfaceFlinger::captureDisplay(uint64_t displayIdOrLayerStack, + const sp<IScreenCaptureListener>& captureListener) { + ui::LayerStack layerStack; + wp<const DisplayDevice> displayWeak; + ui::Size size; + ui::Dataspace dataspace; + { + Mutex::Autolock lock(mStateLock); + auto display = getDisplayDeviceLocked(PhysicalDisplayId{displayIdOrLayerStack}); - class LayerRenderArea : public RenderArea { - public: - LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop, - int32_t reqWidth, int32_t reqHeight, Dataspace reqDataSpace, - bool childrenOnly, const Rect& displayViewport) - : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR, reqDataSpace, displayViewport), - mLayer(layer), - mCrop(crop), - mNeedsFiltering(false), - mFlinger(flinger), - mChildrenOnly(childrenOnly) {} - const ui::Transform& getTransform() const override { return mTransform; } - Rect getBounds() const override { return mLayer->getBufferSize(mLayer->getDrawingState()); } - int getHeight() const override { - return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight(); - } - int getWidth() const override { - return mLayer->getBufferSize(mLayer->getDrawingState()).getWidth(); - } - bool isSecure() const override { return false; } - bool needsFiltering() const override { return mNeedsFiltering; } - sp<const DisplayDevice> getDisplayDevice() const override { return nullptr; } - Rect getSourceCrop() const override { - if (mCrop.isEmpty()) { - return getBounds(); - } else { - return mCrop; - } + // Fall back to first display whose layer stack matches. + if (!display) { + const auto layerStack = static_cast<ui::LayerStack>(displayIdOrLayerStack); + display = findDisplay(WithLayerStack(layerStack)); } - class ReparentForDrawing { - public: - const sp<Layer>& oldParent; - const sp<Layer>& newParent; - - ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent, - const Rect& drawingBounds) - : oldParent(oldParent), newParent(newParent) { - // Compute and cache the bounds for the new parent layer. - newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform(), - 0.f /* shadowRadius */); - oldParent->setChildrenDrawingParent(newParent); - } - ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); } - }; - - void render(std::function<void()> drawLayers) override { - const Rect sourceCrop = getSourceCrop(); - // no need to check rotation because there is none - mNeedsFiltering = sourceCrop.width() != getReqWidth() || - sourceCrop.height() != getReqHeight(); - if (!mChildrenOnly) { - mTransform = mLayer->getTransform().inverse(); - drawLayers(); - } else { - uint32_t w = static_cast<uint32_t>(getWidth()); - uint32_t h = static_cast<uint32_t>(getHeight()); - // In the "childrenOnly" case we reparent the children to a screenshot - // layer which has no properties set and which does not draw. - sp<ContainerLayer> screenshotParentLayer = - mFlinger->getFactory().createContainerLayer({mFlinger, nullptr, - "Screenshot Parent"s, w, h, 0, - LayerMetadata()}); - - ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop); - drawLayers(); - } + if (!display) { + return NAME_NOT_FOUND; } - private: - const sp<Layer> mLayer; - const Rect mCrop; + layerStack = display->getLayerStack(); + displayWeak = display; - ui::Transform mTransform; - bool mNeedsFiltering; + size = display->getLayerStackSpaceRect().getSize(); - SurfaceFlinger* mFlinger; - const bool mChildrenOnly; + dataspace = + pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode); + } + + RenderAreaFuture renderAreaFuture = ftl::defer([=] { + return DisplayRenderArea::create(displayWeak, Rect(), size, dataspace, + false /* useIdentityTransform */, + false /* captureSecureLayers */); + }); + + auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) { + traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor); }; - int reqWidth = 0; - int reqHeight = 0; + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, + ui::PixelFormat::RGBA_8888, false /* allowProtected */, + false /* grayscale */, captureListener); +} + +status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, + const sp<IScreenCaptureListener>& captureListener) { + ATRACE_CALL(); + + status_t validate = validateScreenshotPermissions(args); + if (validate != OK) { + return validate; + } + + ui::Size reqSize; sp<Layer> parent; - Rect crop(sourceCrop); + Rect crop(args.sourceCrop); std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers; - Rect displayViewport; + Rect layerStackSpaceRect; + ui::Dataspace dataspace; + bool captureSecureLayers; + + // Call this before holding mStateLock to avoid any deadlocking. + bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); + { Mutex::Autolock lock(mStateLock); - parent = fromHandleLocked(layerHandleBinder).promote(); + parent = fromHandleLocked(args.layerHandle).promote(); if (parent == nullptr || parent->isRemovedFromCurrentState()) { ALOGE("captureLayers called with an invalid or removed parent"); return NAME_NOT_FOUND; } - const int uid = IPCThreadState::self()->getCallingUid(); - const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM; - if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) { + if (!canCaptureBlackoutContent && + parent->getDrawingState().flags & layer_state_t::eLayerSecure) { ALOGW("Attempting to capture secure layer: PERMISSION_DENIED"); return PERMISSION_DENIED; } - Rect parentSourceBounds = parent->getCroppedBufferSize(parent->getCurrentState()); - if (sourceCrop.width() <= 0) { + Rect parentSourceBounds = parent->getCroppedBufferSize(parent->getDrawingState()); + if (args.sourceCrop.width() <= 0) { crop.left = 0; crop.right = parentSourceBounds.getWidth(); } - if (sourceCrop.height() <= 0) { + if (args.sourceCrop.height() <= 0) { crop.top = 0; crop.bottom = parentSourceBounds.getHeight(); } - if (crop.isEmpty() || frameScale <= 0.0f) { + if (crop.isEmpty() || args.frameScaleX <= 0.0f || args.frameScaleY <= 0.0f) { // Error out if the layer has no source bounds (i.e. they are boundless) and a source // crop was not specified, or an invalid frame scale was provided. return BAD_VALUE; } - reqWidth = crop.width() * frameScale; - reqHeight = crop.height() * frameScale; + reqSize = ui::Size(crop.width() * args.frameScaleX, crop.height() * args.frameScaleY); - for (const auto& handle : excludeHandles) { + for (const auto& handle : args.excludeHandles) { sp<Layer> excludeLayer = fromHandleLocked(handle).promote(); if (excludeLayer != nullptr) { excludeLayers.emplace(excludeLayer); @@ -5551,30 +6129,48 @@ status_t SurfaceFlinger::captureLayers( } } - const auto display = getDisplayByLayerStack(parent->getLayerStack()); + const auto display = findDisplay(WithLayerStack(parent->getLayerStack())); if (!display) { return NAME_NOT_FOUND; } - displayViewport = display->getViewport(); + layerStackSpaceRect = display->getLayerStackSpaceRect(); + + // The dataspace is depended on the color mode of display, that could use non-native mode + // (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes, + // 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) { + const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode; + dataspace = pickDataspaceFromColorMode(colorMode); + } + + captureSecureLayers = args.captureSecureLayers && display->isSecure(); } // mStateLock // really small crop or frameScale - if (reqWidth <= 0) { - reqWidth = 1; + if (reqSize.width <= 0) { + reqSize.width = 1; } - if (reqHeight <= 0) { - reqHeight = 1; + if (reqSize.height <= 0) { + reqSize.height = 1; } - LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, reqDataspace, childrenOnly, - displayViewport); - auto traverseLayers = [parent, childrenOnly, - &excludeLayers](const LayerVector::Visitor& visitor) { + bool childrenOnly = args.childrenOnly; + RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr<RenderArea> { + return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace, + childrenOnly, layerStackSpaceRect, + captureSecureLayers); + }); + + auto traverseLayers = [parent, args, excludeLayers](const LayerVector::Visitor& visitor) { parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { if (!layer->isVisible()) { return; - } else if (childrenOnly && layer == parent.get()) { + } else if (args.childrenOnly && layer == parent.get()) { + return; + } else if (args.uid != CaptureArgs::UNSET_UID && args.uid != layer->getOwnerUid()) { return; } @@ -5590,84 +6186,129 @@ status_t SurfaceFlinger::captureLayers( }); }; - bool outCapturedSecureLayers = false; - return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false, - outCapturedSecureLayers); + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, args.allowProtected, args.grayscale, + captureListener); } -status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, +status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, - sp<GraphicBuffer>* outBuffer, - const ui::PixelFormat reqPixelFormat, - bool useIdentityTransform, - bool& outCapturedSecureLayers) { + ui::Size bufferSize, ui::PixelFormat reqPixelFormat, + bool allowProtected, bool grayscale, + const sp<IScreenCaptureListener>& captureListener) { ATRACE_CALL(); - // TODO(b/116112787) Make buffer usage a parameter. - const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER; - *outBuffer = - getFactory().createGraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(), - static_cast<android_pixel_format>(reqPixelFormat), 1, - usage, "screenshot"); + // Loop over all visible layers to see whether there's any protected layer. A protected layer is + // typically a layer with DRM contents, or have the GRALLOC_USAGE_PROTECTED set on the buffer. + // A protected layer has no implication on whether it's secure, which is explicitly set by + // application to avoid being screenshot or drawn via unsecure display. + 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(); + } + + const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE | + (hasProtectedLayer && allowProtected && supportsProtected + ? GRALLOC_USAGE_PROTECTED + : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); + sp<GraphicBuffer> buffer = + getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(), + static_cast<android_pixel_format>(reqPixelFormat), + 1 /* layerCount */, usage, "screenshot"); + + 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); + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, texture, + false /* regionSampling */, grayscale, captureListener); +} + +status_t SurfaceFlinger::captureScreenCommon( + RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, + const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, + bool grayscale, const sp<IScreenCaptureListener>& captureListener) { + ATRACE_CALL(); - return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform, - false /* regionSampling */, outCapturedSecureLayers); -} + if (captureListener == nullptr) { + ALOGE("capture screen must provide a capture listener callback"); + return BAD_VALUE; + } -status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - const sp<GraphicBuffer>& buffer, - bool useIdentityTransform, bool regionSampling, - bool& outCapturedSecureLayers) { - const int uid = IPCThreadState::self()->getCallingUid(); - const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM; + bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); - status_t result; - int syncFd; + 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; + } + 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; + } - do { - std::tie(result, syncFd) = - schedule([&] { - if (mRefreshPending) { - ATRACE_NAME("Skipping screenshot for now"); - return std::make_pair(EAGAIN, -1); - } + status_t result = NO_ERROR; + renderArea->render([&] { + result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, + canCaptureBlackoutContent, regionSampling, grayscale, + captureResults); + }); - status_t result = NO_ERROR; - int fd = -1; + captureResults.result = result; + captureListener->onScreenCaptureCompleted(captureResults); + })); - Mutex::Autolock lock(mStateLock); - renderArea.render([&] { - result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(), - useIdentityTransform, forSystem, &fd, - regionSampling, outCapturedSecureLayers); - }); + return NO_ERROR; +} - return std::make_pair(result, fd); - }).get(); - } while (result == EAGAIN); +status_t SurfaceFlinger::renderScreenImplLocked( + const RenderArea& renderArea, TraverseLayersFunction traverseLayers, + const std::shared_ptr<renderengine::ExternalTexture>& buffer, + bool canCaptureBlackoutContent, bool regionSampling, bool grayscale, + ScreenCaptureResults& captureResults) { + ATRACE_CALL(); - if (result == NO_ERROR) { - sync_wait(syncFd, -1); - close(syncFd); - } + traverseLayers([&](Layer* layer) { + captureResults.capturedSecureLayers = + captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure()); + }); - return result; -} + const bool useProtected = buffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED; -void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - ANativeWindowBuffer* buffer, bool useIdentityTransform, - bool regionSampling, int* outSyncFd) { - ATRACE_CALL(); + // 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; + } + + captureResults.buffer = buffer->getBuffer(); + captureResults.capturedDataspace = renderArea.getReqDataSpace(); const auto reqWidth = renderArea.getReqWidth(); const auto reqHeight = renderArea.getReqHeight(); const auto sourceCrop = renderArea.getSourceCrop(); const auto transform = renderArea.getTransform(); const auto rotation = renderArea.getRotationFlags(); - const auto& displayViewport = renderArea.getDisplayViewport(); + const auto& layerStackSpaceRect = renderArea.getLayerStackSpaceRect(); renderengine::DisplaySettings clientCompositionDisplay; std::vector<compositionengine::LayerFE::LayerSettings> clientCompositionLayers; @@ -5681,6 +6322,9 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace(); clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance; + const float colorSaturation = grayscale ? 0 : 1; + clientCompositionDisplay.colorTransform = calculateColorMatrix(colorSaturation); + const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill()); compositionengine::LayerFE::LayerSettings fillLayer; @@ -5694,21 +6338,26 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, const auto display = renderArea.getDisplayDevice(); std::vector<Layer*> renderedLayers; Region clearRegion = Region::INVALID_REGION; + bool disableBlurs = false; traverseLayers([&](Layer* layer) { - const bool supportProtectedContent = false; + disableBlurs |= layer->getDrawingState().sidebandStream != nullptr; + Region clip(renderArea.getBounds()); compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ clip, - useIdentityTransform, layer->needsFilteringForScreenshots(display.get(), transform) || renderArea.needsFiltering(), renderArea.isSecure(), - supportProtectedContent, + useProtected, clearRegion, - displayViewport, + layerStackSpaceRect, clientCompositionDisplay.outputDataspace, true, /* realContentIsVisible */ false, /* clearContent */ + disableBlurs ? compositionengine::LayerFE::ClientCompositionTargetSettings:: + BlurSetting::Disabled + : compositionengine::LayerFE::ClientCompositionTargetSettings:: + BlurSetting::Enabled, }; std::vector<compositionengine::LayerFE::LayerSettings> results = layer->prepareClientCompositionList(targetSettings); @@ -5723,11 +6372,13 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, settings.backgroundBlurRadius = 0; } } + clientCompositionLayers.insert(clientCompositionLayers.end(), std::make_move_iterator(results.begin()), std::make_move_iterator(results.end())); renderedLayers.push_back(layer); } + }); std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers( @@ -5741,51 +6392,29 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, // there is no need for synchronization with the GPU. base::unique_fd bufferFence; base::unique_fd drawFence; - getRenderEngine().useProtectedContext(false); - getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, - /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence); + getRenderEngine().useProtectedContext(useProtected); - *outSyncFd = drawFence.release(); + const constexpr bool kUseFramebufferCache = false; + getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, + kUseFramebufferCache, std::move(bufferFence), &drawFence); - if (*outSyncFd >= 0) { - sp<Fence> releaseFence = new Fence(dup(*outSyncFd)); + if (drawFence >= 0) { + sp<Fence> releaseFence = new Fence(dup(drawFence)); for (auto* layer : renderedLayers) { layer->onLayerDisplayed(releaseFence); } } -} -status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - ANativeWindowBuffer* buffer, - bool useIdentityTransform, bool forSystem, - int* outSyncFd, bool regionSampling, - bool& outCapturedSecureLayers) { - ATRACE_CALL(); - - traverseLayers([&](Layer* layer) { - outCapturedSecureLayers = - outCapturedSecureLayers || (layer->isVisible() && layer->isSecure()); - }); + captureResults.fence = new Fence(drawFence.release()); + // Always switch back to unprotected context. + getRenderEngine().useProtectedContext(false); - // 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 (outCapturedSecureLayers && !forSystem) { - ALOGW("FB is protected: PERMISSION_DENIED"); - return PERMISSION_DENIED; - } - renderScreenImplLocked(renderArea, traverseLayers, buffer, useIdentityTransform, regionSampling, - outSyncFd); return NO_ERROR; } void SurfaceFlinger::setInputWindowsFinished() { Mutex::Autolock _l(mStateLock); - - mPendingSyncInputWindows = false; - - mTransactionCV.broadcast(); + signalSynchronousTransactions(CountDownLatch::eSyncInputWindows); } // --------------------------------------------------------------------------- @@ -5802,28 +6431,31 @@ void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& layersSortedByZ.traverseInReverseZOrder(stateSet, visitor); } -void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& display, - const LayerVector::Visitor& visitor) { +void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const int32_t uid, + const LayerVector::Visitor& visitor) { // 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(display->getLayerStack(), false)) { + if (!layer->belongsToDisplay(layerStack)) { continue; } // relative layers are traversed in Layer::traverseInZOrder layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - if (!layer->belongsToDisplay(display->getLayerStack(), false)) { + if (layer->getPrimaryDisplayOnly()) { return; } if (!layer->isVisible()) { return; } + if (uid != CaptureArgs::UNSET_UID && layer->getOwnerUid() != uid) { + return; + } visitor(layer); }); } } -status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( +status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( const sp<DisplayDevice>& display, const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) { Mutex::Autolock lock(mStateLock); @@ -5832,39 +6464,34 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( "Can only set override policy on the primary display"); LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy"); + if (mDebugDisplayModeSetByBackdoor) { + // ignore this request as mode is overridden by backdoor + return NO_ERROR; + } + if (!display->isPrimary()) { - // TODO(b/144711714): For non-primary displays we should be able to set an active config - // as well. For now, just call directly to setActiveConfigWithConstraints but ideally - // it should go thru setDesiredActiveConfig, similar to primary display. - ALOGV("setAllowedDisplayConfigsInternal for non-primary display"); - const auto displayId = display->getId(); - LOG_ALWAYS_FATAL_IF(!displayId); + // TODO(b/144711714): For non-primary displays we should be able to set an active mode + // as well. For now, just call directly to initiateModeChange but ideally + // it should go thru setDesiredActiveMode, similar to primary display. + ALOGV("%s for non-primary display", __func__); + const auto displayId = display->getPhysicalId(); hal::VsyncPeriodChangeConstraints constraints; constraints.desiredTimeNanos = systemTime(); constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0}; - if (getHwComposer().setActiveConfigWithConstraints(*displayId, - policy->defaultConfig.value(), - constraints, &timeline) < 0) { + if (display->initiateModeChange(policy->defaultMode, constraints, &timeline) != NO_ERROR) { return BAD_VALUE; } if (timeline.refreshRequired) { repaintEverythingForHWC(); } - display->setActiveConfig(policy->defaultConfig); - const nsecs_t vsyncPeriod = getHwComposer() - .getConfigs(*displayId)[policy->defaultConfig.value()] - ->getVsyncPeriod(); - mScheduler->onNonPrimaryDisplayConfigChanged(mAppConnectionHandle, display->getId()->value, - policy->defaultConfig, vsyncPeriod); - return NO_ERROR; - } - - if (mDebugDisplayConfigSetByBackdoor) { - // ignore this request as config is overridden by backdoor + display->setActiveMode(policy->defaultMode); + const nsecs_t vsyncPeriod = display->getMode(policy->defaultMode)->getVsyncPeriod(); + mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, displayId, + policy->defaultMode, vsyncPeriod); return NO_ERROR; } @@ -5879,48 +6506,41 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( } scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy(); - ALOGV("Setting desired display config specs: defaultConfig: %d primaryRange: [%.0f %.0f]" - " expandedRange: [%.0f %.0f]", - currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min, - currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min, - currentPolicy.appRequestRange.max); + ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str()); // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might // be depending in this callback. - const nsecs_t vsyncPeriod = - mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig()) - .getVsyncPeriod(); - mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, display->getId()->value, - display->getActiveConfig(), vsyncPeriod); + const auto activeMode = display->getActiveMode(); + const nsecs_t vsyncPeriod = activeMode->getVsyncPeriod(); + const auto physicalId = display->getPhysicalId(); + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId, activeMode->getId(), + vsyncPeriod); toggleKernelIdleTimer(); - auto configId = mScheduler->getPreferredConfigId(); - auto& preferredRefreshRate = configId - ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId) - // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind. - : mRefreshRateConfigs->getRefreshRateFromConfigId(currentPolicy.defaultConfig); - ALOGV("trying to switch to Scheduler preferred config %d (%s)", - preferredRefreshRate.getConfigId().value(), preferredRefreshRate.getName().c_str()); - - if (isDisplayConfigAllowed(preferredRefreshRate.getConfigId())) { - ALOGV("switching to Scheduler preferred config %d", - preferredRefreshRate.getConfigId().value()); - setDesiredActiveConfig( - {preferredRefreshRate.getConfigId(), Scheduler::ConfigEvent::Changed}); + auto modeId = mScheduler->getPreferredModeId(); + auto preferredRefreshRate = modeId + ? mRefreshRateConfigs->getRefreshRateFromModeId(*modeId) + // NOTE: Choose the default mode ID, if Scheduler doesn't have one in mind. + : mRefreshRateConfigs->getRefreshRateFromModeId(currentPolicy.defaultMode); + ALOGV("trying to switch to Scheduler preferred mode %d (%s)", + preferredRefreshRate.getModeId().value(), preferredRefreshRate.getName().c_str()); + + if (isDisplayModeAllowed(preferredRefreshRate.getModeId())) { + ALOGV("switching to Scheduler preferred display mode %d", + preferredRefreshRate.getModeId().value()); + setDesiredActiveMode({preferredRefreshRate.getModeId(), Scheduler::ModeEvent::Changed}); } else { - LOG_ALWAYS_FATAL("Desired config not allowed: %d", - preferredRefreshRate.getConfigId().value()); + LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", + preferredRefreshRate.getModeId().value()); } return NO_ERROR; } -status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, - int32_t defaultConfig, - float primaryRefreshRateMin, - float primaryRefreshRateMax, - float appRequestRefreshRateMin, - float appRequestRefreshRateMax) { +status_t SurfaceFlinger::setDesiredDisplayModeSpecs( + const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching, + float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin, + float appRequestRefreshRateMax) { ATRACE_CALL(); if (!displayToken) { @@ -5930,35 +6550,37 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& display auto future = schedule([=]() -> status_t { const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken)); if (!display) { - ALOGE("Attempt to set desired display configs for invalid display token %p", + ALOGE("Attempt to set desired display modes for invalid display token %p", displayToken.get()); return NAME_NOT_FOUND; } else if (display->isVirtual()) { - ALOGW("Attempt to set desired display configs for virtual display"); + ALOGW("Attempt to set desired display modes for virtual display"); return INVALID_OPERATION; } else { using Policy = scheduler::RefreshRateConfigs::Policy; - const Policy policy{HwcConfigIndexType(defaultConfig), - {primaryRefreshRateMin, primaryRefreshRateMax}, - {appRequestRefreshRateMin, appRequestRefreshRateMax}}; + const Policy policy{DisplayModeId(defaultMode), + allowGroupSwitching, + {Fps(primaryRefreshRateMin), Fps(primaryRefreshRateMax)}, + {Fps(appRequestRefreshRateMin), Fps(appRequestRefreshRateMax)}}; constexpr bool kOverridePolicy = false; - return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy); + return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy); } }); return future.get(); } -status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, - int32_t* outDefaultConfig, - float* outPrimaryRefreshRateMin, - float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, - float* outAppRequestRefreshRateMax) { +status_t SurfaceFlinger::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, + ui::DisplayModeId* outDefaultMode, + bool* outAllowGroupSwitching, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) { ATRACE_CALL(); - if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin || + if (!displayToken || !outDefaultMode || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) { return BAD_VALUE; } @@ -5972,38 +6594,34 @@ status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& display if (display->isPrimary()) { scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy(); - *outDefaultConfig = policy.defaultConfig.value(); - *outPrimaryRefreshRateMin = policy.primaryRange.min; - *outPrimaryRefreshRateMax = policy.primaryRange.max; - *outAppRequestRefreshRateMin = policy.appRequestRange.min; - *outAppRequestRefreshRateMax = policy.appRequestRange.max; + *outDefaultMode = policy.defaultMode.value(); + *outAllowGroupSwitching = policy.allowGroupSwitching; + *outPrimaryRefreshRateMin = policy.primaryRange.min.getValue(); + *outPrimaryRefreshRateMax = policy.primaryRange.max.getValue(); + *outAppRequestRefreshRateMin = policy.appRequestRange.min.getValue(); + *outAppRequestRefreshRateMax = policy.appRequestRange.max.getValue(); return NO_ERROR; } else if (display->isVirtual()) { return INVALID_OPERATION; } else { - const auto displayId = display->getId(); - LOG_FATAL_IF(!displayId); - - *outDefaultConfig = getHwComposer().getActiveConfigIndex(*displayId); - auto vsyncPeriod = getHwComposer().getActiveConfig(*displayId)->getVsyncPeriod(); - *outPrimaryRefreshRateMin = 1e9f / vsyncPeriod; - *outPrimaryRefreshRateMax = 1e9f / vsyncPeriod; - *outAppRequestRefreshRateMin = 1e9f / vsyncPeriod; - *outAppRequestRefreshRateMax = 1e9f / vsyncPeriod; + const auto activeMode = display->getActiveMode(); + *outDefaultMode = activeMode->getId().value(); + *outAllowGroupSwitching = false; + auto vsyncPeriod = activeMode->getVsyncPeriod(); + *outPrimaryRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue(); + *outPrimaryRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue(); + *outAppRequestRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue(); + *outAppRequestRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue(); return NO_ERROR; } } -void SurfaceFlinger::SetInputWindowsListener::onSetInputWindowsFinished() { - mFlinger->setInputWindowsFinished(); -} - wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) { Mutex::Autolock _l(mStateLock); return fromHandleLocked(handle); } -wp<Layer> SurfaceFlinger::fromHandleLocked(const sp<IBinder>& handle) { +wp<Layer> SurfaceFlinger::fromHandleLocked(const sp<IBinder>& handle) const { BBinder* b = nullptr; if (handle) { b = handle->localBinder(); @@ -6020,12 +6638,17 @@ wp<Layer> SurfaceFlinger::fromHandleLocked(const sp<IBinder>& handle) { void SurfaceFlinger::onLayerFirstRef(Layer* layer) { mNumLayers++; - mScheduler->registerLayer(layer); + if (!layer->isRemovedFromCurrentState()) { + mScheduler->registerLayer(layer); + } } void SurfaceFlinger::onLayerDestroyed(Layer* layer) { mNumLayers--; - removeFromOffscreenLayers(layer); + removeHierarchyFromOffscreenLayers(layer); + if (!layer->isRemovedFromCurrentState()) { + mScheduler->deregisterLayer(layer); + } } // WARNING: ONLY CALL THIS FROM LAYER DTOR @@ -6035,15 +6658,15 @@ void SurfaceFlinger::onLayerDestroyed(Layer* layer) { // from dangling children layers such that they are not reachable from the // Drawing state nor the offscreen layer list // See b/141111965 -void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) { +void SurfaceFlinger::removeHierarchyFromOffscreenLayers(Layer* layer) { for (auto& child : layer->getCurrentChildren()) { mOffscreenLayers.emplace(child.get()); } mOffscreenLayers.erase(layer); } -void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) { - getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id); +void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) { + mOffscreenLayers.erase(layer); } status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, @@ -6075,8 +6698,9 @@ const std::unordered_map<std::string, uint32_t>& SurfaceFlinger::getGenericLayer } status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility) { - if (!ValidateFrameRate(frameRate, compatibility, "SurfaceFlinger::setFrameRate")) { + int8_t compatibility, int8_t changeFrameRateStrategy) { + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "SurfaceFlinger::setFrameRate")) { return BAD_VALUE; } @@ -6088,10 +6712,12 @@ status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, ALOGE("Attempt to set frame rate on a layer that no longer exists"); return BAD_VALUE; } - + const auto strategy = + Layer::FrameRate::convertChangeFrameRateStrategy(changeFrameRateStrategy); if (layer->setFrameRate( - Layer::FrameRate(frameRate, - Layer::FrameRate::convertCompatibility(compatibility)))) { + Layer::FrameRate(Fps{frameRate}, + Layer::FrameRate::convertCompatibility(compatibility), + strategy))) { setTransactionFlags(eTraversalNeeded); } } else { @@ -6117,16 +6743,15 @@ status_t SurfaceFlinger::acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); // This is a little racy, but not in a way that hurts anything. As we grab the - // defaultConfig from the display manager policy, we could be setting a new display - // manager policy, leaving us using a stale defaultConfig. The defaultConfig doesn't - // matter for the override policy though, since we set allowGroupSwitching to true, so - // it's not a problem. + // 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.defaultConfig = - mRefreshRateConfigs->getDisplayManagerPolicy().defaultConfig; + overridePolicy.defaultMode = mRefreshRateConfigs->getDisplayManagerPolicy().defaultMode; overridePolicy.allowGroupSwitching = true; constexpr bool kOverridePolicy = true; - result = setDesiredDisplayConfigSpecsInternal(display, overridePolicy, kOverridePolicy); + result = setDesiredDisplayModeSpecsInternal(display, overridePolicy, kOverridePolicy); } if (result == NO_ERROR) { @@ -6166,17 +6791,35 @@ void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() { if (mFrameRateFlexibilityTokenCount == 0) { const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); constexpr bool kOverridePolicy = true; - status_t result = setDesiredDisplayConfigSpecsInternal(display, {}, kOverridePolicy); + status_t result = setDesiredDisplayModeSpecsInternal(display, {}, kOverridePolicy); LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token"); } })); } +status_t SurfaceFlinger::setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, + const FrameTimelineInfo& frameTimelineInfo) { + Mutex::Autolock lock(mStateLock); + if (!authenticateSurfaceTextureLocked(surface)) { + ALOGE("Attempt to set frame timeline info on an unrecognized IGraphicBufferProducer"); + return BAD_VALUE; + } + + sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer(); + if (layer == nullptr) { + ALOGE("Attempt to set frame timeline info on a layer that no longer exists"); + return BAD_VALUE; + } + + layer->setFrameTimelineInfoForBuffer(frameTimelineInfo); + return NO_ERROR; +} + void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { static_cast<void>(schedule([=] { std::unique_ptr<RefreshRateOverlay> overlay; if (enable) { - overlay = std::make_unique<RefreshRateOverlay>(*this); + overlay = std::make_unique<RefreshRateOverlay>(*this, mRefreshRateOverlaySpinner); } { @@ -6188,13 +6831,165 @@ void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { if (const auto display = getDefaultDisplayDeviceLocked()) { mRefreshRateOverlay->setViewport(display->getSize()); + mRefreshRateOverlay->changeRefreshRate(display->getActiveMode()->getFps()); } - - mRefreshRateOverlay->changeRefreshRate(mRefreshRateConfigs->getCurrentRefreshRate()); } })); } +status_t SurfaceFlinger::addTransactionTraceListener( + const sp<gui::ITransactionTraceListener>& listener) { + if (!listener) { + return BAD_VALUE; + } + + mInterceptor->addTransactionTraceListener(listener); + + return NO_ERROR; +} + +int SurfaceFlinger::getGPUContextPriority() { + return getRenderEngine().getContextPriority(); +} + +int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, + std::chrono::nanoseconds presentLatency) { + auto pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs(); + if (presentLatency.count() % refreshRate.getPeriodNsecs()) { + pipelineDepth++; + } + return std::max(1ll, pipelineDepth - 1); +} + +status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { + const auto maxSupportedRefreshRate = mRefreshRateConfigs->getSupportedRefreshRateRange().max; + *buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate); + 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(); + } + return mRefreshRateConfigs->getCurrentRefreshRate().getFps(); + }(); + return getMaxAcquiredBufferCountForRefreshRate(refreshRate); +} + +int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const { + const auto vsyncConfig = mVsyncConfiguration->getConfigsForRefreshRate(refreshRate).late; + const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration; + 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(); + if (!layer) { + ALOGE("Invalid layer %p", state->layer.unsafe_get()); + return nullptr; + } + + sp<Layer> parent; + bool allowAddRoot = state->addToRoot; + if (state->initialParent != nullptr) { + parent = fromHandleLocked(state->initialParent.promote()).promote(); + if (parent == nullptr) { + ALOGE("Invalid parent %p", state->initialParent.unsafe_get()); + allowAddRoot = false; + } + } else if (state->initialParentLayer != nullptr) { + parent = state->initialParentLayer.promote(); + allowAddRoot = false; + } + + if (parent == nullptr && allowAddRoot) { + layer->setIsAtRoot(true); + mCurrentState.layersSortedByZ.add(layer); + } else if (parent == nullptr) { + layer->onRemovedFromCurrentState(); + } else if (parent->isRemovedFromCurrentState()) { + parent->addChild(layer); + layer->onRemovedFromCurrentState(); + } else { + parent->addChild(layer); + } + + layer->updateTransformHint(mDefaultDisplayTransformHint); + + 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(); })); +} + +void SurfaceFlinger::notifyRegionSamplingThread() { + if (!mLumaSampling || !mRegionSamplingThread) { + return; + } + + mRegionSamplingThread->onCompositionComplete(mEventQueue->nextExpectedInvalidate()); +} + } // namespace android #if defined(__gl_h_) @@ -6206,4 +7001,4 @@ void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { #endif // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" |