diff options
| author | 2024-03-29 21:58:45 +0000 | |
|---|---|---|
| committer | 2024-04-01 21:21:26 +0000 | |
| commit | 70c2ee640a6bdcfd4bc2d0fecd20f9ff4a662896 (patch) | |
| tree | 860ca4fe822d6ab3102fdc216fe7036ccf9d608b | |
| parent | d96534c47ef132f2da600cd565ed2e3cc12ff7ad (diff) | |
Create test for screenshots with null snapshots
Snapshots can be null when a layer is offscreen and unparented.
The best way to simulate this in a test is to mirror an offscreen
layer and check if the screenshot path works. Also adds more
informative screenshot deubg logs.
Bug: b/331874495, b/331923495
Test: atest ScreenCapturetest
Change-Id: I4fcd822f00e6427ebaf899756f95e6790b035544
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 23 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/LayerTransactionTest.h | 4 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/ScreenCapture_test.cpp | 23 |
3 files changed, 42 insertions, 8 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 949a030c1f..81697da5e1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -7838,17 +7838,19 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, status_t validate = validateScreenshotPermissions(args); if (validate != OK) { + ALOGD("Permission denied to captureDisplay"); invokeScreenCaptureError(validate, captureListener); return; } if (!args.displayToken) { + ALOGD("Invalid display token to captureDisplay"); invokeScreenCaptureError(BAD_VALUE, captureListener); return; } if (args.captureSecureLayers && !hasCaptureBlackoutContentPermission()) { - ALOGE("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT"); + ALOGD("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT"); invokeScreenCaptureError(PERMISSION_DENIED, captureListener); return; } @@ -7861,6 +7863,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, Mutex::Autolock lock(mStateLock); sp<DisplayDevice> display = getDisplayDeviceLocked(args.displayToken); if (!display) { + ALOGD("Unable to find display device for captureDisplay"); invokeScreenCaptureError(NAME_NOT_FOUND, captureListener); return; } @@ -7877,7 +7880,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, if (excludeLayer != UNASSIGNED_LAYER_ID) { excludeLayerIds.emplace(excludeLayer); } else { - ALOGW("Invalid layer handle passed as excludeLayer to captureDisplay"); + ALOGD("Invalid layer handle passed as excludeLayer to captureDisplay"); invokeScreenCaptureError(NAME_NOT_FOUND, captureListener); return; } @@ -7915,6 +7918,7 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args const auto display = getDisplayDeviceLocked(displayId); if (!display) { + ALOGD("Unable to find display device for captureDisplay"); invokeScreenCaptureError(NAME_NOT_FOUND, captureListener); return; } @@ -7932,7 +7936,7 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args constexpr auto kMaxTextureSize = 16384; if (size.width <= 0 || size.height <= 0 || size.width >= kMaxTextureSize || size.height >= kMaxTextureSize) { - ALOGE("capture display resolved to invalid size %d x %d", size.width, size.height); + ALOGD("captureDisplay resolved to invalid size %d x %d", size.width, size.height); invokeScreenCaptureError(BAD_VALUE, captureListener); return; } @@ -7979,6 +7983,7 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, status_t validate = validateScreenshotPermissions(args); if (validate != OK) { + ALOGD("Permission denied to captureLayers"); invokeScreenCaptureError(validate, captureListener); return; } @@ -7990,7 +7995,7 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, ui::Dataspace dataspace = args.dataspace; if (args.captureSecureLayers && !hasCaptureBlackoutContentPermission()) { - ALOGE("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT"); + ALOGD("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT"); invokeScreenCaptureError(PERMISSION_DENIED, captureListener); return; } @@ -8000,7 +8005,7 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, parent = LayerHandle::getLayer(args.layerHandle); if (parent == nullptr) { - ALOGE("captureLayers called with an invalid or removed parent"); + ALOGD("captureLayers called with an invalid or removed parent"); invokeScreenCaptureError(NAME_NOT_FOUND, captureListener); return; } @@ -8019,6 +8024,7 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, if (crop.isEmpty() || args.frameScaleX <= 0.0f || args.frameScaleY <= 0.0f) { // Error out if the layer has no source bounds (i.e. they are boundless) and a source // crop was not specified, or an invalid frame scale was provided. + ALOGD("Boundless layer, unspecified crop, or invalid frame scale to captureLayers"); invokeScreenCaptureError(BAD_VALUE, captureListener); return; } @@ -8029,7 +8035,7 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, if (excludeLayer != UNASSIGNED_LAYER_ID) { excludeLayerIds.emplace(excludeLayer); } else { - ALOGW("Invalid layer handle passed as excludeLayer to captureLayers"); + ALOGD("Invalid layer handle passed as excludeLayer to captureLayers"); invokeScreenCaptureError(NAME_NOT_FOUND, captureListener); return; } @@ -8038,7 +8044,7 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, // really small crop or frameScale if (reqSize.width <= 0 || reqSize.height <= 0) { - ALOGW("Failed to captureLayers: crop or scale too small"); + ALOGD("Failed to captureLayers: crop or scale too small"); invokeScreenCaptureError(BAD_VALUE, captureListener); return; } @@ -8103,7 +8109,7 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } if (captureListener == nullptr) { - ALOGE("capture screen must provide a capture listener callback"); + ALOGD("capture screen must provide a capture listener callback"); invokeScreenCaptureError(BAD_VALUE, captureListener); return; } @@ -9869,6 +9875,7 @@ binder::Status SurfaceComposerAIDL::captureDisplayById( std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId)); mFlinger->captureDisplay(*id, args, captureListener); } else { + ALOGD("Permission denied to captureDisplayById"); invokeScreenCaptureError(PERMISSION_DENIED, captureListener); } return binderStatusFromStatusT(NO_ERROR); diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index c9af432513..5b056d0765 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -106,6 +106,10 @@ protected: return colorLayer; } + sp<SurfaceControl> mirrorSurface(SurfaceControl* mirrorFromSurface) { + return mClient->mirrorSurface(mirrorFromSurface); + } + ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) { // wait for previous transactions (such as setSize) to complete Transaction().apply(true); diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index 18262f664a..9a78550d00 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -1039,6 +1039,29 @@ TEST_F(ScreenCaptureTest, CaptureHdrLayer) { ASSERT_TRUE(mCapture->capturedHdrLayers()); } +TEST_F(ScreenCaptureTest, captureOffscreenNullSnapshot) { + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32, + ISurfaceComposerClient::eFXSurfaceBufferState, + mBGSurfaceControl.get())); + + // A mirrored layer will not have a snapshot. Testing an offscreen mirrored layer + // ensures that the screenshot path handles cases where snapshots are null. + sp<SurfaceControl> mirroredLayer; + ASSERT_NO_FATAL_FAILURE(mirroredLayer = mirrorSurface(layer.get())); + + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = mirroredLayer->getHandle(); + captureArgs.sourceCrop = Rect(0, 0, 1, 1); + + // Screenshot path should only use the children of the layer hierarchy so + // that it will not create a new snapshot. A snapshot would otherwise be + // created to pass on the properties of the parent, which is not needed + // for the purposes of this test since we explicitly want a null snapshot. + captureArgs.childrenOnly = true; + ScreenCapture::captureLayers(&mCapture, captureArgs); +} + // In the following tests we verify successful skipping of a parent layer, // so we use the same verification logic and only change how we mutate // the parent layer to verify that various properties are ignored. |