diff options
| author | 2020-10-14 16:16:37 -0700 | |
|---|---|---|
| committer | 2020-10-14 18:17:07 -0700 | |
| commit | 05cc0118549860866a9b77057e39af86906cfef5 (patch) | |
| tree | 1e37c9d3e01a52941f15c3b1421cb6f642b8b0de | |
| parent | d72053c65b445fc116f0d4be6f9cf35e784eba8c (diff) | |
[SurfaceFlinger] Add support to capture protected contents.
Previously capture screen always use an unprotected buffer, which forces
layers with protected contents to be black. This patch enables to
capture with a protected buffer when there's no unprotected access to
the contents.
Bug: b/146180867
Test: N/A
Change-Id: I03a2c4f8d093f390abf7afb90aa3f7ea82f27ce4
| -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 8594ab3bd5..e243e23344 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -593,6 +593,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; } @@ -606,6 +607,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 ff395ecfb4..034899d12d 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -319,6 +319,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); }; @@ -346,7 +354,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 02593d57ef..86dd0fc5a8 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -467,7 +467,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; } @@ -679,7 +679,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 575da268f9..e457659ec1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5383,6 +5383,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(); @@ -5431,46 +5470,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, @@ -5505,7 +5505,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, @@ -5626,18 +5627,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), @@ -5648,7 +5663,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(); @@ -5706,6 +5721,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. @@ -5750,14 +5767,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, @@ -5795,7 +5811,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); @@ -5807,6 +5823,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); |