summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/SurfaceFlinger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp4007
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, &param) != 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"