diff options
| -rw-r--r-- | libs/gui/LayerState.cpp | 2 | ||||
| -rw-r--r-- | libs/gui/include/gui/LayerState.h | 10 | ||||
| -rw-r--r-- | services/surfaceflinger/Layer.h | 5 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 116 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 9 |
5 files changed, 86 insertions, 56 deletions
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 782f35ae02..2e4d279a5b 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -586,6 +586,7 @@ status_t CaptureArgs::write(Parcel& output) const { SAFE_PARCEL(output.writeBool, captureSecureLayers); SAFE_PARCEL(output.writeInt32, uid); SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(dataspace)); + SAFE_PARCEL(output.writeBool, allowProtected); return NO_ERROR; } @@ -599,6 +600,7 @@ status_t CaptureArgs::read(const Parcel& input) { SAFE_PARCEL(input.readInt32, &uid); SAFE_PARCEL(input.readInt32, &value); dataspace = static_cast<ui::Dataspace>(value); + SAFE_PARCEL(input.readBool, &allowProtected); return NO_ERROR; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index abd7d64809..5942fd03af 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -318,6 +318,14 @@ struct CaptureArgs { // NOTE: In normal cases, we want the screen to be captured in display's colorspace. ui::Dataspace dataspace = ui::Dataspace::UNKNOWN; + // The receiver of the capture can handle protected buffer. A protected buffer has + // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour. + // Any read/write access from unprotected context will result in undefined behaviour. + // Protected contents are typically DRM contents. This has no direct implication to the + // secure property of the surface, which is specified by the application explicitly to avoid + // the contents being accessed/captured by screenshot or unsecure display. + bool allowProtected = false; + virtual status_t write(Parcel& output) const; virtual status_t read(const Parcel& input); }; @@ -345,7 +353,7 @@ struct ScreenCaptureResults { sp<GraphicBuffer> buffer; bool capturedSecureLayers{false}; ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB}; - status_t result = NO_ERROR; + status_t result = OK; status_t write(Parcel& output) const; status_t read(const Parcel& input); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4b7c611e26..7112cbc435 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -465,7 +465,7 @@ public: virtual bool canReceiveInput() const; /* - * isProtected - true if the layer may contain protected content in the + * isProtected - true if the layer may contain protected contents in the * GRALLOC_USAGE_PROTECTED sense. */ virtual bool isProtected() const { return false; } @@ -677,7 +677,8 @@ public: /* * isSecure - true if this surface is secure, that is if it prevents - * screenshots or VNC servers. + * screenshots or VNC servers. A surface can be set to be secure by the + * application, being secure doesn't mean the surface has DRM contents. */ bool isSecure() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8ab3ed3f91..964bd015f2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5381,6 +5381,45 @@ static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) { return PERMISSION_DENIED; } +status_t SurfaceFlinger::setSchedFifo(bool enabled) { + static constexpr int kFifoPriority = 2; + static constexpr int kOtherPriority = 0; + + struct sched_param param = {0}; + int sched_policy; + if (enabled) { + sched_policy = SCHED_FIFO; + param.sched_priority = kFifoPriority; + } else { + sched_policy = SCHED_OTHER; + param.sched_priority = kOtherPriority; + } + + if (sched_setscheduler(0, sched_policy, ¶m) != 0) { + return -errno; + } + return NO_ERROR; +} + +sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) { + if (const sp<IBinder> displayToken = + getPhysicalDisplayTokenLocked(PhysicalDisplayId{displayOrLayerStack})) { + return getDisplayDeviceLocked(displayToken); + } + // 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; + } + } + return nullptr; +} + status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { ATRACE_CALL(); @@ -5429,46 +5468,7 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, captureListener); -} - -status_t SurfaceFlinger::setSchedFifo(bool enabled) { - static constexpr int kFifoPriority = 2; - static constexpr int kOtherPriority = 0; - - struct sched_param param = {0}; - int sched_policy; - if (enabled) { - sched_policy = SCHED_FIFO; - param.sched_priority = kFifoPriority; - } else { - sched_policy = SCHED_OTHER; - param.sched_priority = kOtherPriority; - } - - if (sched_setscheduler(0, sched_policy, ¶m) != 0) { - return -errno; - } - return NO_ERROR; -} - -sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) { - if (const sp<IBinder> displayToken = - getPhysicalDisplayTokenLocked(PhysicalDisplayId{displayOrLayerStack})) { - return getDisplayDeviceLocked(displayToken); - } - // 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; - } - } - return nullptr; + args.pixelFormat, args.allowProtected, captureListener); } status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, @@ -5503,7 +5503,8 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, - ui::PixelFormat::RGBA_8888, captureListener); + ui::PixelFormat::RGBA_8888, false /* allowProtected */, + captureListener); } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -5624,18 +5625,32 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, captureListener); + args.pixelFormat, args.allowProtected, captureListener); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, + const bool allowProtected, 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; + // 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) { + traverseLayers([&](Layer* layer) { + hasProtectedLayer = hasProtectedLayer || (layer->isVisible() && layer->isProtected()); + }); + } + + const uint32_t usage = 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), @@ -5646,7 +5661,7 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, - sp<GraphicBuffer>& buffer, bool regionSampling, + sp<GraphicBuffer>& buffer, const bool regionSampling, const sp<IScreenCaptureListener>& captureListener) { ATRACE_CALL(); @@ -5704,6 +5719,8 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure()); }); + const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED; + // We allow the system server to take screenshots of secure layers for // use in situations like the Screen-rotation animation and place // the impetus on WindowManager to not persist them. @@ -5748,14 +5765,13 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, std::vector<Layer*> renderedLayers; Region clearRegion = Region::INVALID_REGION; traverseLayers([&](Layer* layer) { - const bool supportProtectedContent = false; Region clip(renderArea.getBounds()); compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ clip, layer->needsFilteringForScreenshots(display.get(), transform) || renderArea.needsFiltering(), renderArea.isSecure(), - supportProtectedContent, + useProtected, clearRegion, layerStackSpaceRect, clientCompositionDisplay.outputDataspace, @@ -5793,7 +5809,7 @@ status_t 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().useProtectedContext(useProtected); getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence); @@ -5805,6 +5821,8 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, layer->onLayerDisplayed(releaseFence); } } + // Always switch back to unprotected context. + getRenderEngine().useProtectedContext(false); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f55dd90789..5bb5a0de82 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -797,13 +797,14 @@ private: // Boot animation, on/off animations and screen capture void startBootAnim(); - status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, - const sp<GraphicBuffer>&, bool forSystem, int* outSyncFd, - bool regionSampling, ScreenCaptureResults&); status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, - ui::PixelFormat, const sp<IScreenCaptureListener>&); + ui::PixelFormat, const bool allowProtected, + const sp<IScreenCaptureListener>&); status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&, bool regionSampling, const sp<IScreenCaptureListener>&); + status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, + const sp<GraphicBuffer>&, bool forSystem, int* outSyncFd, + bool regionSampling, ScreenCaptureResults&); sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock); |