[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
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 575da26..e457659 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5383,6 +5383,45 @@
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 @@
};
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 @@
};
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 @@
};
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,
TraverseLayersFunction traverseLayers,
- sp<GraphicBuffer>& buffer, bool regionSampling,
+ sp<GraphicBuffer>& buffer, const bool regionSampling,
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
@@ -5706,6 +5721,8 @@
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 @@
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 @@
// 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 @@
layer->onLayerDisplayed(releaseFence);
}
}
+ // Always switch back to unprotected context.
+ getRenderEngine().useProtectedContext(false);
return NO_ERROR;
}