Loading services/surfaceflinger/RegionSamplingThread.cpp +23 −10 Original line number Diff line number Diff line Loading @@ -348,17 +348,30 @@ void RegionSamplingThread::captureSample() { constexpr bool kGrayscale = false; constexpr bool kIsProtected = false; if (const auto fenceResult = mFlinger.captureScreenshot(SurfaceFlinger::RenderAreaBuilderVariant( std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds, sampledBounds.getSize(), ui::Dataspace::V0_SRGB, kHintForSeamlessTransition, true /* captureSecureLayers */, displayWeak), getLayerSnapshotsFn, buffer, kRegionSampling, kGrayscale, kIsProtected, nullptr) SurfaceFlinger::RenderAreaBuilderVariant renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds, sampledBounds.getSize(), ui::Dataspace::V0_SRGB, kHintForSeamlessTransition, true /* captureSecureLayers */, displayWeak); FenceResult fenceResult; if (FlagManager::getInstance().single_hop_screenshot() && FlagManager::getInstance().ce_fence_promise()) { std::vector<sp<LayerFE>> layerFEs; auto displayState = mFlinger.getDisplayAndLayerSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layerFEs); fenceResult = mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale, kIsProtected, nullptr, displayState, layerFEs) .get(); fenceResult.ok()) { } else { fenceResult = mFlinger.captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, buffer, kRegionSampling, kGrayscale, kIsProtected, nullptr) .get(); } if (fenceResult.ok()) { fenceResult.value()->waitForever(LOG_TAG); } Loading services/surfaceflinger/SurfaceFlinger.cpp +185 −71 Original line number Diff line number Diff line Loading @@ -8127,12 +8127,15 @@ void SurfaceFlinger::attachReleaseFenceFutureToLayer(Layer* layer, LayerFE* laye owningLayer->prepareReleaseCallbacks(std::move(futureFence), layerStack); } bool SurfaceFlinger::layersHasProtectedLayer( const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const { // 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. bool SurfaceFlinger::layersHasProtectedLayer(const std::vector<sp<LayerFE>>& layers) const { bool protectedLayerFound = false; for (auto& [_, layerFe] : layers) { for (auto& layerFE : layers) { protectedLayerFound |= (layerFe->mSnapshot->isVisible && layerFe->mSnapshot->hasProtectedContent); (layerFE->mSnapshot->isVisible && layerFE->mSnapshot->hasProtectedContent); if (protectedLayerFound) { break; } Loading @@ -8140,6 +8143,26 @@ bool SurfaceFlinger::layersHasProtectedLayer( return protectedLayerFound; } // Getting layer snapshots and display should take place on main thread. // Accessing display requires mStateLock, and contention for this lock // is reduced when grabbed from the main thread, thus also reducing // risk of deadlocks. std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getDisplayAndLayerSnapshotsFromMainThread( RenderAreaBuilderVariant& renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, std::vector<sp<LayerFE>>& layerFEs) { return mScheduler ->schedule([=, this, &renderAreaBuilder, &layerFEs]() REQUIRES(kMainThreadContext) { auto layers = getLayerSnapshotsFn(); for (auto& [layer, layerFE] : layers) { attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK); } layerFEs = extractLayerFEs(layers); return getDisplayStateFromRenderAreaBuilder(renderAreaBuilder); }) .get(); } void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, Loading @@ -8155,15 +8178,17 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil return; } // 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. if (FlagManager::getInstance().single_hop_screenshot() && FlagManager::getInstance().ce_fence_promise()) { std::vector<sp<LayerFE>> layerFEs; auto displayState = getDisplayAndLayerSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layerFEs); const bool supportsProtected = getRenderEngine().supportsProtectedContent(); bool hasProtectedLayer = false; if (allowProtected && supportsProtected) { auto layers = mScheduler->schedule([=]() { return getLayerSnapshotsFn(); }).get(); hasProtectedLayer = layersHasProtectedLayer(layers); hasProtectedLayer = layersHasProtectedLayer(layerFEs); } const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected; const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | Loading @@ -8189,13 +8214,49 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil renderengine::impl::ExternalTexture::Usage:: WRITEABLE); auto futureFence = captureScreenshot(renderAreaBuilder, getLayerSnapshotsFn, texture, false /* regionSampling */, grayscale, isProtected, captureListener); captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, grayscale, isProtected, captureListener, displayState, layerFEs); futureFence.get(); } else { const bool supportsProtected = getRenderEngine().supportsProtectedContent(); bool hasProtectedLayer = false; if (allowProtected && supportsProtected) { auto layers = mScheduler->schedule([=]() { return getLayerSnapshotsFn(); }).get(); hasProtectedLayer = layersHasProtectedLayer(extractLayerFEs(layers)); } const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected; const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE | (isProtected ? 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(); if (bufferStatus != OK) { // Animations may end up being really janky, but don't crash here. // Otherwise an irreponsible process may cause an SF crash by allocating // too much. ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus); invokeScreenCaptureError(bufferStatus, captureListener); return; } const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared< renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), renderengine::impl::ExternalTexture::Usage:: WRITEABLE); auto futureFence = captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, texture, false /* regionSampling */, grayscale, isProtected, captureListener); futureFence.get(); } } const sp<const DisplayDevice> SurfaceFlinger::getRenderAreaDisplay( RenderAreaBuilderVariant& renderAreaBuilder, OutputCompositionState& state) { std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getDisplayStateFromRenderAreaBuilder(RenderAreaBuilderVariant& renderAreaBuilder) { sp<const DisplayDevice> display = nullptr; { Mutex::Autolock lock(mStateLock); Loading Loading @@ -8224,24 +8285,64 @@ const sp<const DisplayDevice> SurfaceFlinger::getRenderAreaDisplay( } if (display != nullptr) { state = display->getCompositionDisplay()->getState(); return std::optional{display->getCompositionDisplay()->getState()}; } } return display; return std::nullopt; } std::vector<std::pair<Layer*, sp<android::LayerFE>>> SurfaceFlinger::getLayerSnapshotsFromMainThread(GetLayerSnapshotsFunction getLayerSnapshotsFn) { auto layers = getLayerSnapshotsFn(); if (FlagManager::getInstance().ce_fence_promise()) { for (auto& [layer, layerFE] : layers) { attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK); } std::vector<sp<LayerFE>> SurfaceFlinger::extractLayerFEs( const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const { std::vector<sp<LayerFE>> layerFEs; layerFEs.reserve(layers.size()); for (const auto& [_, layerFE] : layers) { layerFEs.push_back(layerFE); } return layers; return layerFEs; } ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, std::optional<OutputCompositionState>& displayState, std::vector<sp<LayerFE>>& layerFEs) { ATRACE_CALL(); ScreenCaptureResults captureResults; std::unique_ptr<const RenderArea> renderArea = std::visit([](auto&& arg) -> std::unique_ptr<RenderArea> { return arg.build(); }, renderAreaBuilder); if (!renderArea) { ALOGW("Skipping screen capture because of invalid render area."); if (captureListener) { captureResults.fenceResult = base::unexpected(NO_MEMORY); captureListener->onScreenCaptureCompleted(captureResults); } return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); } // Empty vector needed to pass into renderScreenImpl for legacy path std::vector<std::pair<Layer*, sp<android::LayerFE>>> layers; ftl::SharedFuture<FenceResult> renderFuture = renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale, isProtected, captureResults, displayState, layers, layerFEs); if (captureListener) { // Defer blocking on renderFuture back to the Binder thread. return ftl::Future(std::move(renderFuture)) .then([captureListener, captureResults = std::move(captureResults)]( FenceResult fenceResult) mutable -> FenceResult { captureResults.fenceResult = std::move(fenceResult); captureListener->onScreenCaptureCompleted(captureResults); return base::unexpected(NO_ERROR); }) .share(); } return renderFuture; } ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshotLegacy( RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener) { Loading @@ -8249,10 +8350,13 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( auto takeScreenshotFn = [=, this, renderAreaBuilder = std::move(renderAreaBuilder)]() REQUIRES( kMainThreadContext) mutable -> ftl::SharedFuture<FenceResult> { auto layers = getLayerSnapshotsFromMainThread(getLayerSnapshotsFn); OutputCompositionState state; const auto display = getRenderAreaDisplay(renderAreaBuilder, state); auto layers = getLayerSnapshotsFn(); if (FlagManager::getInstance().ce_fence_promise()) { for (auto& [layer, layerFE] : layers) { attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK); } } auto displayState = getDisplayStateFromRenderAreaBuilder(renderAreaBuilder); ScreenCaptureResults captureResults; std::unique_ptr<const RenderArea> renderArea = Loading @@ -8268,9 +8372,10 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); } auto layerFEs = extractLayerFEs(layers); ftl::SharedFuture<FenceResult> renderFuture = renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale, isProtected, captureResults, display, state, layers); isProtected, captureResults, displayState, layers, layerFEs); if (captureListener) { // Defer blocking on renderFuture back to the Binder thread. Loading Loading @@ -8303,11 +8408,11 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( std::unique_ptr<const RenderArea> renderArea, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults& captureResults, const sp<const DisplayDevice> display, const OutputCompositionState& state, std::vector<std::pair<Layer*, sp<android::LayerFE>>>& layers) { std::optional<OutputCompositionState>& displayState, std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, std::vector<sp<LayerFE>>& layerFEs) { ATRACE_CALL(); for (auto& [_, layerFE] : layers) { for (auto& layerFE : layerFEs) { frontend::LayerSnapshot* snapshot = layerFE->mSnapshot.get(); captureResults.capturedSecureLayers |= (snapshot->isVisible && snapshot->isSecure); captureResults.capturedHdrLayers |= isHdrLayer(*snapshot); Loading @@ -8330,7 +8435,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( const bool enableLocalTonemapping = FlagManager::getInstance().local_tonemap_screenshots() && !renderArea->getHintForSeamlessTransition(); if (display != nullptr) { if (displayState) { const auto& state = displayState.value(); captureResults.capturedDataspace = pickBestDataspace(requestedDataspace, state, captureResults.capturedHdrLayers, renderArea->getHintForSeamlessTransition()); Loading Loading @@ -8365,18 +8471,18 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( captureResults.buffer = capturedBuffer->getBuffer(); ui::LayerStack layerStack{ui::DEFAULT_LAYER_STACK}; if (!layers.empty()) { const sp<LayerFE>& layerFE = layers.back().second; if (!layerFEs.empty()) { const sp<LayerFE>& layerFE = layerFEs.back(); layerStack = layerFE->getCompositionState()->outputFilter.layerStack; } auto copyLayerFEs = [&layers]() { std::vector<sp<compositionengine::LayerFE>> layerFEs; layerFEs.reserve(layers.size()); for (const auto& [_, layerFE] : layers) { layerFEs.push_back(layerFE); auto copyLayerFEs = [&layerFEs]() { std::vector<sp<compositionengine::LayerFE>> ceLayerFEs; ceLayerFEs.reserve(layerFEs.size()); for (const auto& layerFE : layerFEs) { ceLayerFEs.push_back(layerFE); } return layerFEs; return ceLayerFEs; }; auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace, Loading Loading @@ -8445,8 +8551,16 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( // // TODO(b/196334700) Once we use RenderEngineThreaded everywhere we can always defer the call // to CompositionEngine::present. auto presentFuture = mRenderEngine->isThreaded() ? ftl::defer(std::move(present)).share() ftl::SharedFuture<FenceResult> presentFuture; if (FlagManager::getInstance().single_hop_screenshot() && FlagManager::getInstance().ce_fence_promise()) { presentFuture = mRenderEngine->isThreaded() ? ftl::yield(present()).share() : mScheduler->schedule(std::move(present)).share(); } else { presentFuture = mRenderEngine->isThreaded() ? ftl::defer(std::move(present)).share() : ftl::yield(present()).share(); } if (!FlagManager::getInstance().ce_fence_promise()) { for (auto& [layer, layerFE] : layers) { Loading services/surfaceflinger/SurfaceFlinger.h +24 −11 Original line number Diff line number Diff line Loading @@ -892,22 +892,35 @@ private: void attachReleaseFenceFutureToLayer(Layer* layer, LayerFE* layerFE, ui::LayerStack layerStack); // Checks if a protected layer exists in a list of layers. bool layersHasProtectedLayer(const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const; bool layersHasProtectedLayer(const std::vector<sp<LayerFE>>& layers) const; using OutputCompositionState = compositionengine::impl::OutputCompositionState; std::optional<OutputCompositionState> getDisplayAndLayerSnapshotsFromMainThread( RenderAreaBuilderVariant& renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, std::vector<sp<LayerFE>>& layerFEs); void captureScreenCommon(RenderAreaBuilderVariant, GetLayerSnapshotsFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, bool grayscale, const sp<IScreenCaptureListener>&); using OutputCompositionState = compositionengine::impl::OutputCompositionState; const sp<const DisplayDevice> getRenderAreaDisplay(RenderAreaBuilderVariant& renderAreaBuilder, OutputCompositionState& state) REQUIRES(kMainThreadContext); std::optional<OutputCompositionState> getDisplayStateFromRenderAreaBuilder( RenderAreaBuilderVariant& renderAreaBuilder) REQUIRES(kMainThreadContext); std::vector<std::pair<Layer*, sp<android::LayerFE>>> getLayerSnapshotsFromMainThread( GetLayerSnapshotsFunction getLayerSnapshotsFn) REQUIRES(kMainThreadContext); // Legacy layer raw pointer is not safe to access outside the main thread. // Creates a new vector consisting only of LayerFEs, which can be safely // accessed outside the main thread. std::vector<sp<LayerFE>> extractLayerFEs( const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const; ftl::SharedFuture<FenceResult> captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, std::optional<OutputCompositionState>& displayState, std::vector<sp<LayerFE>>& layerFEs); ftl::SharedFuture<FenceResult> captureScreenshotLegacy( RenderAreaBuilderVariant, GetLayerSnapshotsFunction, const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, bool grayscale, bool isProtected, const sp<IScreenCaptureListener>&); Loading @@ -916,9 +929,9 @@ private: std::unique_ptr<const RenderArea>, const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults&, const sp<const DisplayDevice> display, const OutputCompositionState& state, std::vector<std::pair<Layer*, sp<android::LayerFE>>>& layers) REQUIRES(kMainThreadContext); std::optional<OutputCompositionState>& displayState, std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, std::vector<sp<LayerFE>>& layerFEs); // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a // matching ownerUid Loading services/surfaceflinger/common/FlagManager.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -150,6 +150,7 @@ void FlagManager::dump(std::string& result) const { DUMP_READ_ONLY_FLAG(override_trusted_overlay); DUMP_READ_ONLY_FLAG(flush_buffer_slots_to_uncache); DUMP_READ_ONLY_FLAG(force_compile_graphite_renderengine); DUMP_READ_ONLY_FLAG(single_hop_screenshot); #undef DUMP_READ_ONLY_FLAG #undef DUMP_SERVER_FLAG Loading Loading @@ -250,6 +251,7 @@ FLAG_MANAGER_READ_ONLY_FLAG(local_tonemap_screenshots, "debug.sf.local_tonemap_s FLAG_MANAGER_READ_ONLY_FLAG(override_trusted_overlay, ""); FLAG_MANAGER_READ_ONLY_FLAG(flush_buffer_slots_to_uncache, ""); FLAG_MANAGER_READ_ONLY_FLAG(force_compile_graphite_renderengine, ""); FLAG_MANAGER_READ_ONLY_FLAG(single_hop_screenshot, ""); /// Trunk stable server flags /// FLAG_MANAGER_SERVER_FLAG(refresh_rate_overlay_on_external_display, "") Loading services/surfaceflinger/common/include/common/FlagManager.h +1 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,7 @@ public: bool override_trusted_overlay() const; bool flush_buffer_slots_to_uncache() const; bool force_compile_graphite_renderengine() const; bool single_hop_screenshot() const; protected: // overridden for unit tests Loading Loading
services/surfaceflinger/RegionSamplingThread.cpp +23 −10 Original line number Diff line number Diff line Loading @@ -348,17 +348,30 @@ void RegionSamplingThread::captureSample() { constexpr bool kGrayscale = false; constexpr bool kIsProtected = false; if (const auto fenceResult = mFlinger.captureScreenshot(SurfaceFlinger::RenderAreaBuilderVariant( std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds, sampledBounds.getSize(), ui::Dataspace::V0_SRGB, kHintForSeamlessTransition, true /* captureSecureLayers */, displayWeak), getLayerSnapshotsFn, buffer, kRegionSampling, kGrayscale, kIsProtected, nullptr) SurfaceFlinger::RenderAreaBuilderVariant renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds, sampledBounds.getSize(), ui::Dataspace::V0_SRGB, kHintForSeamlessTransition, true /* captureSecureLayers */, displayWeak); FenceResult fenceResult; if (FlagManager::getInstance().single_hop_screenshot() && FlagManager::getInstance().ce_fence_promise()) { std::vector<sp<LayerFE>> layerFEs; auto displayState = mFlinger.getDisplayAndLayerSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layerFEs); fenceResult = mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale, kIsProtected, nullptr, displayState, layerFEs) .get(); fenceResult.ok()) { } else { fenceResult = mFlinger.captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, buffer, kRegionSampling, kGrayscale, kIsProtected, nullptr) .get(); } if (fenceResult.ok()) { fenceResult.value()->waitForever(LOG_TAG); } Loading
services/surfaceflinger/SurfaceFlinger.cpp +185 −71 Original line number Diff line number Diff line Loading @@ -8127,12 +8127,15 @@ void SurfaceFlinger::attachReleaseFenceFutureToLayer(Layer* layer, LayerFE* laye owningLayer->prepareReleaseCallbacks(std::move(futureFence), layerStack); } bool SurfaceFlinger::layersHasProtectedLayer( const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const { // 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. bool SurfaceFlinger::layersHasProtectedLayer(const std::vector<sp<LayerFE>>& layers) const { bool protectedLayerFound = false; for (auto& [_, layerFe] : layers) { for (auto& layerFE : layers) { protectedLayerFound |= (layerFe->mSnapshot->isVisible && layerFe->mSnapshot->hasProtectedContent); (layerFE->mSnapshot->isVisible && layerFE->mSnapshot->hasProtectedContent); if (protectedLayerFound) { break; } Loading @@ -8140,6 +8143,26 @@ bool SurfaceFlinger::layersHasProtectedLayer( return protectedLayerFound; } // Getting layer snapshots and display should take place on main thread. // Accessing display requires mStateLock, and contention for this lock // is reduced when grabbed from the main thread, thus also reducing // risk of deadlocks. std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getDisplayAndLayerSnapshotsFromMainThread( RenderAreaBuilderVariant& renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, std::vector<sp<LayerFE>>& layerFEs) { return mScheduler ->schedule([=, this, &renderAreaBuilder, &layerFEs]() REQUIRES(kMainThreadContext) { auto layers = getLayerSnapshotsFn(); for (auto& [layer, layerFE] : layers) { attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK); } layerFEs = extractLayerFEs(layers); return getDisplayStateFromRenderAreaBuilder(renderAreaBuilder); }) .get(); } void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, Loading @@ -8155,15 +8178,17 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil return; } // 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. if (FlagManager::getInstance().single_hop_screenshot() && FlagManager::getInstance().ce_fence_promise()) { std::vector<sp<LayerFE>> layerFEs; auto displayState = getDisplayAndLayerSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layerFEs); const bool supportsProtected = getRenderEngine().supportsProtectedContent(); bool hasProtectedLayer = false; if (allowProtected && supportsProtected) { auto layers = mScheduler->schedule([=]() { return getLayerSnapshotsFn(); }).get(); hasProtectedLayer = layersHasProtectedLayer(layers); hasProtectedLayer = layersHasProtectedLayer(layerFEs); } const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected; const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | Loading @@ -8189,13 +8214,49 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil renderengine::impl::ExternalTexture::Usage:: WRITEABLE); auto futureFence = captureScreenshot(renderAreaBuilder, getLayerSnapshotsFn, texture, false /* regionSampling */, grayscale, isProtected, captureListener); captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, grayscale, isProtected, captureListener, displayState, layerFEs); futureFence.get(); } else { const bool supportsProtected = getRenderEngine().supportsProtectedContent(); bool hasProtectedLayer = false; if (allowProtected && supportsProtected) { auto layers = mScheduler->schedule([=]() { return getLayerSnapshotsFn(); }).get(); hasProtectedLayer = layersHasProtectedLayer(extractLayerFEs(layers)); } const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected; const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE | (isProtected ? 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(); if (bufferStatus != OK) { // Animations may end up being really janky, but don't crash here. // Otherwise an irreponsible process may cause an SF crash by allocating // too much. ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus); invokeScreenCaptureError(bufferStatus, captureListener); return; } const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared< renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), renderengine::impl::ExternalTexture::Usage:: WRITEABLE); auto futureFence = captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, texture, false /* regionSampling */, grayscale, isProtected, captureListener); futureFence.get(); } } const sp<const DisplayDevice> SurfaceFlinger::getRenderAreaDisplay( RenderAreaBuilderVariant& renderAreaBuilder, OutputCompositionState& state) { std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getDisplayStateFromRenderAreaBuilder(RenderAreaBuilderVariant& renderAreaBuilder) { sp<const DisplayDevice> display = nullptr; { Mutex::Autolock lock(mStateLock); Loading Loading @@ -8224,24 +8285,64 @@ const sp<const DisplayDevice> SurfaceFlinger::getRenderAreaDisplay( } if (display != nullptr) { state = display->getCompositionDisplay()->getState(); return std::optional{display->getCompositionDisplay()->getState()}; } } return display; return std::nullopt; } std::vector<std::pair<Layer*, sp<android::LayerFE>>> SurfaceFlinger::getLayerSnapshotsFromMainThread(GetLayerSnapshotsFunction getLayerSnapshotsFn) { auto layers = getLayerSnapshotsFn(); if (FlagManager::getInstance().ce_fence_promise()) { for (auto& [layer, layerFE] : layers) { attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK); } std::vector<sp<LayerFE>> SurfaceFlinger::extractLayerFEs( const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const { std::vector<sp<LayerFE>> layerFEs; layerFEs.reserve(layers.size()); for (const auto& [_, layerFE] : layers) { layerFEs.push_back(layerFE); } return layers; return layerFEs; } ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, std::optional<OutputCompositionState>& displayState, std::vector<sp<LayerFE>>& layerFEs) { ATRACE_CALL(); ScreenCaptureResults captureResults; std::unique_ptr<const RenderArea> renderArea = std::visit([](auto&& arg) -> std::unique_ptr<RenderArea> { return arg.build(); }, renderAreaBuilder); if (!renderArea) { ALOGW("Skipping screen capture because of invalid render area."); if (captureListener) { captureResults.fenceResult = base::unexpected(NO_MEMORY); captureListener->onScreenCaptureCompleted(captureResults); } return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); } // Empty vector needed to pass into renderScreenImpl for legacy path std::vector<std::pair<Layer*, sp<android::LayerFE>>> layers; ftl::SharedFuture<FenceResult> renderFuture = renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale, isProtected, captureResults, displayState, layers, layerFEs); if (captureListener) { // Defer blocking on renderFuture back to the Binder thread. return ftl::Future(std::move(renderFuture)) .then([captureListener, captureResults = std::move(captureResults)]( FenceResult fenceResult) mutable -> FenceResult { captureResults.fenceResult = std::move(fenceResult); captureListener->onScreenCaptureCompleted(captureResults); return base::unexpected(NO_ERROR); }) .share(); } return renderFuture; } ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshotLegacy( RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener) { Loading @@ -8249,10 +8350,13 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( auto takeScreenshotFn = [=, this, renderAreaBuilder = std::move(renderAreaBuilder)]() REQUIRES( kMainThreadContext) mutable -> ftl::SharedFuture<FenceResult> { auto layers = getLayerSnapshotsFromMainThread(getLayerSnapshotsFn); OutputCompositionState state; const auto display = getRenderAreaDisplay(renderAreaBuilder, state); auto layers = getLayerSnapshotsFn(); if (FlagManager::getInstance().ce_fence_promise()) { for (auto& [layer, layerFE] : layers) { attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK); } } auto displayState = getDisplayStateFromRenderAreaBuilder(renderAreaBuilder); ScreenCaptureResults captureResults; std::unique_ptr<const RenderArea> renderArea = Loading @@ -8268,9 +8372,10 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); } auto layerFEs = extractLayerFEs(layers); ftl::SharedFuture<FenceResult> renderFuture = renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale, isProtected, captureResults, display, state, layers); isProtected, captureResults, displayState, layers, layerFEs); if (captureListener) { // Defer blocking on renderFuture back to the Binder thread. Loading Loading @@ -8303,11 +8408,11 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( std::unique_ptr<const RenderArea> renderArea, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults& captureResults, const sp<const DisplayDevice> display, const OutputCompositionState& state, std::vector<std::pair<Layer*, sp<android::LayerFE>>>& layers) { std::optional<OutputCompositionState>& displayState, std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, std::vector<sp<LayerFE>>& layerFEs) { ATRACE_CALL(); for (auto& [_, layerFE] : layers) { for (auto& layerFE : layerFEs) { frontend::LayerSnapshot* snapshot = layerFE->mSnapshot.get(); captureResults.capturedSecureLayers |= (snapshot->isVisible && snapshot->isSecure); captureResults.capturedHdrLayers |= isHdrLayer(*snapshot); Loading @@ -8330,7 +8435,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( const bool enableLocalTonemapping = FlagManager::getInstance().local_tonemap_screenshots() && !renderArea->getHintForSeamlessTransition(); if (display != nullptr) { if (displayState) { const auto& state = displayState.value(); captureResults.capturedDataspace = pickBestDataspace(requestedDataspace, state, captureResults.capturedHdrLayers, renderArea->getHintForSeamlessTransition()); Loading Loading @@ -8365,18 +8471,18 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( captureResults.buffer = capturedBuffer->getBuffer(); ui::LayerStack layerStack{ui::DEFAULT_LAYER_STACK}; if (!layers.empty()) { const sp<LayerFE>& layerFE = layers.back().second; if (!layerFEs.empty()) { const sp<LayerFE>& layerFE = layerFEs.back(); layerStack = layerFE->getCompositionState()->outputFilter.layerStack; } auto copyLayerFEs = [&layers]() { std::vector<sp<compositionengine::LayerFE>> layerFEs; layerFEs.reserve(layers.size()); for (const auto& [_, layerFE] : layers) { layerFEs.push_back(layerFE); auto copyLayerFEs = [&layerFEs]() { std::vector<sp<compositionengine::LayerFE>> ceLayerFEs; ceLayerFEs.reserve(layerFEs.size()); for (const auto& layerFE : layerFEs) { ceLayerFEs.push_back(layerFE); } return layerFEs; return ceLayerFEs; }; auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace, Loading Loading @@ -8445,8 +8551,16 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( // // TODO(b/196334700) Once we use RenderEngineThreaded everywhere we can always defer the call // to CompositionEngine::present. auto presentFuture = mRenderEngine->isThreaded() ? ftl::defer(std::move(present)).share() ftl::SharedFuture<FenceResult> presentFuture; if (FlagManager::getInstance().single_hop_screenshot() && FlagManager::getInstance().ce_fence_promise()) { presentFuture = mRenderEngine->isThreaded() ? ftl::yield(present()).share() : mScheduler->schedule(std::move(present)).share(); } else { presentFuture = mRenderEngine->isThreaded() ? ftl::defer(std::move(present)).share() : ftl::yield(present()).share(); } if (!FlagManager::getInstance().ce_fence_promise()) { for (auto& [layer, layerFE] : layers) { Loading
services/surfaceflinger/SurfaceFlinger.h +24 −11 Original line number Diff line number Diff line Loading @@ -892,22 +892,35 @@ private: void attachReleaseFenceFutureToLayer(Layer* layer, LayerFE* layerFE, ui::LayerStack layerStack); // Checks if a protected layer exists in a list of layers. bool layersHasProtectedLayer(const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const; bool layersHasProtectedLayer(const std::vector<sp<LayerFE>>& layers) const; using OutputCompositionState = compositionengine::impl::OutputCompositionState; std::optional<OutputCompositionState> getDisplayAndLayerSnapshotsFromMainThread( RenderAreaBuilderVariant& renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, std::vector<sp<LayerFE>>& layerFEs); void captureScreenCommon(RenderAreaBuilderVariant, GetLayerSnapshotsFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, bool grayscale, const sp<IScreenCaptureListener>&); using OutputCompositionState = compositionengine::impl::OutputCompositionState; const sp<const DisplayDevice> getRenderAreaDisplay(RenderAreaBuilderVariant& renderAreaBuilder, OutputCompositionState& state) REQUIRES(kMainThreadContext); std::optional<OutputCompositionState> getDisplayStateFromRenderAreaBuilder( RenderAreaBuilderVariant& renderAreaBuilder) REQUIRES(kMainThreadContext); std::vector<std::pair<Layer*, sp<android::LayerFE>>> getLayerSnapshotsFromMainThread( GetLayerSnapshotsFunction getLayerSnapshotsFn) REQUIRES(kMainThreadContext); // Legacy layer raw pointer is not safe to access outside the main thread. // Creates a new vector consisting only of LayerFEs, which can be safely // accessed outside the main thread. std::vector<sp<LayerFE>> extractLayerFEs( const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const; ftl::SharedFuture<FenceResult> captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, std::optional<OutputCompositionState>& displayState, std::vector<sp<LayerFE>>& layerFEs); ftl::SharedFuture<FenceResult> captureScreenshotLegacy( RenderAreaBuilderVariant, GetLayerSnapshotsFunction, const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, bool grayscale, bool isProtected, const sp<IScreenCaptureListener>&); Loading @@ -916,9 +929,9 @@ private: std::unique_ptr<const RenderArea>, const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults&, const sp<const DisplayDevice> display, const OutputCompositionState& state, std::vector<std::pair<Layer*, sp<android::LayerFE>>>& layers) REQUIRES(kMainThreadContext); std::optional<OutputCompositionState>& displayState, std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, std::vector<sp<LayerFE>>& layerFEs); // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a // matching ownerUid Loading
services/surfaceflinger/common/FlagManager.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -150,6 +150,7 @@ void FlagManager::dump(std::string& result) const { DUMP_READ_ONLY_FLAG(override_trusted_overlay); DUMP_READ_ONLY_FLAG(flush_buffer_slots_to_uncache); DUMP_READ_ONLY_FLAG(force_compile_graphite_renderengine); DUMP_READ_ONLY_FLAG(single_hop_screenshot); #undef DUMP_READ_ONLY_FLAG #undef DUMP_SERVER_FLAG Loading Loading @@ -250,6 +251,7 @@ FLAG_MANAGER_READ_ONLY_FLAG(local_tonemap_screenshots, "debug.sf.local_tonemap_s FLAG_MANAGER_READ_ONLY_FLAG(override_trusted_overlay, ""); FLAG_MANAGER_READ_ONLY_FLAG(flush_buffer_slots_to_uncache, ""); FLAG_MANAGER_READ_ONLY_FLAG(force_compile_graphite_renderengine, ""); FLAG_MANAGER_READ_ONLY_FLAG(single_hop_screenshot, ""); /// Trunk stable server flags /// FLAG_MANAGER_SERVER_FLAG(refresh_rate_overlay_on_external_display, "") Loading
services/surfaceflinger/common/include/common/FlagManager.h +1 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,7 @@ public: bool override_trusted_overlay() const; bool flush_buffer_slots_to_uncache() const; bool force_compile_graphite_renderengine() const; bool single_hop_screenshot() const; protected: // overridden for unit tests Loading