Immediately fail screenshots if requesting secure without permission.
The screenshot logic will only fail to capture when requesting secure if
there is any secure layers on screen. This is confusing since the caller
shouldn't be allowed to apss in captureSecureLayers for screenshots
without permission regardless if there are any secure layers on screen.
This makes the screenshot permission model simpler
1. If there are secure layers on screen, it will be blacked out
2. If the caller has CAPTURE_BLACKOUT_CONTENT and requests
captureSecureLayers, they will get a screenshot that contains the
secure layers
3. If the caller doesn't have CAPTURE_BLACKOUT_CONTENT and requests
captureSecureLayers, they will get a permission denied callback.
Test: ScreenCaptureTest
Bug: 313697941
Change-Id: Iba64989d74ebc2076218f643a8940806e59b6b97
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 85c16b7..5fc22c5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -7539,6 +7539,12 @@
return;
}
+ if (args.captureSecureLayers && !hasCaptureBlackoutContentPermission()) {
+ ALOGE("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT");
+ invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
+ return;
+ }
+
wp<const DisplayDevice> displayWeak;
ui::LayerStack layerStack;
ui::Size reqSize(args.width, args.height);
@@ -7669,8 +7675,11 @@
std::unordered_set<uint32_t> excludeLayerIds;
ui::Dataspace dataspace = args.dataspace;
- // Call this before holding mStateLock to avoid any deadlocking.
- bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
+ if (args.captureSecureLayers && !hasCaptureBlackoutContentPermission()) {
+ ALOGE("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT");
+ invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
+ return;
+ }
{
Mutex::Autolock lock(mStateLock);
@@ -7682,13 +7691,6 @@
return;
}
- if (!canCaptureBlackoutContent &&
- parent->getDrawingState().flags & layer_state_t::eLayerSecure) {
- ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
- invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
- return;
- }
-
Rect parentSourceBounds = parent->getCroppedBufferSize(parent->getDrawingState());
if (args.sourceCrop.width() <= 0) {
crop.left = 0;
@@ -7866,8 +7868,6 @@
bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
- bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
-
auto future = mScheduler->schedule(
[=, renderAreaFuture = std::move(renderAreaFuture)]() FTL_FAKE_GUARD(
kMainThreadContext) mutable -> ftl::SharedFuture<FenceResult> {
@@ -7885,8 +7885,7 @@
ftl::SharedFuture<FenceResult> renderFuture;
renderArea->render([&]() FTL_FAKE_GUARD(kMainThreadContext) {
renderFuture = renderScreenImpl(renderArea, getLayerSnapshots, buffer,
- canCaptureBlackoutContent, regionSampling,
- grayscale, captureResults);
+ regionSampling, grayscale, captureResults);
});
if (captureListener) {
@@ -7913,9 +7912,8 @@
ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
std::shared_ptr<const RenderArea> renderArea, GetLayerSnapshotsFunction getLayerSnapshots,
- const std::shared_ptr<renderengine::ExternalTexture>& buffer,
- bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
- ScreenCaptureResults& captureResults) {
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
+ bool grayscale, ScreenCaptureResults& captureResults) {
ATRACE_CALL();
auto layers = getLayerSnapshots();
@@ -7930,14 +7928,6 @@
layerFE->mSnapshot->geomLayerTransform.inverse();
}
- // 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 ftl::yield<FenceResult>(base::unexpected(PERMISSION_DENIED)).share();
- }
-
auto capturedBuffer = buffer;
auto requestedDataspace = renderArea->getReqDataSpace();