Allow offscreen mirrored layers to be captured.
If an offscreen layer is valid and has content, we should be able to
take a screen capture of it.
If we're mirroring content, but it's not on screen, we need
to ensure updateMirrorInfo is called to get the updated hierarchy. This
will allow the mirror content to get properly screenshot
Test: screencapture offscreen
Test: MirrorLayerTest
Test: ScreenCaptureTest
Change-Id: I31f806eb616e2d6f800da6328c9878a3e47d6a14
Bug: 188222480
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 9cf7c09..d192a2d 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -52,17 +52,6 @@
}
};
-TEST_F(InvalidHandleTest, createSurfaceInvalidParentHandle) {
- // The createSurface is scheduled now, we could still get a created surface from createSurface.
- // Should verify if it actually added into current state by checking the screenshot.
- auto notSc = mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0,
- mNotSc->getHandle());
- LayerCaptureArgs args;
- args.layerHandle = notSc->getHandle();
- ScreenCaptureResults captureResults;
- ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
-}
-
TEST_F(InvalidHandleTest, captureLayersInvalidHandle) {
LayerCaptureArgs args;
args.layerHandle = mNotSc->getHandle();
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index 3ec6da9..a921aa8 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -273,6 +273,61 @@
}
}
+// Test that a mirror layer can be screenshot when offscreen
+TEST_F(MirrorLayerTest, OffscreenMirrorScreenshot) {
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ui::DisplayMode mode;
+ SurfaceComposerClient::getActiveDisplayMode(display, &mode);
+ const ui::Size& size = mode.resolution;
+
+ sp<SurfaceControl> grandchild =
+ createLayer("Grandchild layer", 50, 50, ISurfaceComposerClient::eFXSurfaceBufferState,
+ mChildLayer.get());
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(grandchild, Color::BLUE, 50, 50));
+ Rect childBounds = Rect(50, 50, 450, 450);
+
+ asTransaction([&](Transaction& t) {
+ t.setCrop(grandchild, Rect(0, 0, 50, 50)).show(grandchild);
+ t.setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+ });
+
+ sp<SurfaceControl> mirrorLayer = nullptr;
+ {
+ // Run as system to get the ACCESS_SURFACE_FLINGER permission when mirroring
+ UIDFaker f(AID_SYSTEM);
+ // Mirror mChildLayer
+ mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+ ASSERT_NE(mirrorLayer, nullptr);
+ }
+
+ // Show the mirror layer, but don't reparent to a layer on screen.
+ Transaction().show(mirrorLayer).apply();
+
+ {
+ SCOPED_TRACE("Offscreen Mirror");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, size.getWidth(), 50), Color::RED);
+ shot->expectColor(Rect(0, 0, 50, size.getHeight()), Color::RED);
+ shot->expectColor(Rect(450, 0, size.getWidth(), size.getHeight()), Color::RED);
+ shot->expectColor(Rect(0, 450, size.getWidth(), size.getHeight()), Color::RED);
+ shot->expectColor(Rect(100, 100, 450, 450), Color::GREEN);
+ shot->expectColor(Rect(50, 50, 100, 100), Color::BLUE);
+ }
+
+ {
+ SCOPED_TRACE("Capture Mirror");
+ // Capture just the mirror layer and child.
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = mirrorLayer->getHandle();
+ captureArgs.sourceCrop = childBounds;
+ std::unique_ptr<ScreenCapture> shot;
+ ScreenCapture::captureLayers(&shot, captureArgs);
+ shot->expectSize(childBounds.width(), childBounds.height());
+ shot->expectColor(Rect(0, 0, 50, 50), Color::BLUE);
+ shot->expectColor(Rect(50, 50, 400, 400), Color::GREEN);
+ }
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 95301b3..f9b3185 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -37,6 +37,8 @@
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
const ui::Size& resolution = mode.resolution;
+ mDisplaySize = resolution;
+
// Background surface
mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(),
resolution.getHeight(), 0);
@@ -72,6 +74,7 @@
sp<SurfaceControl> mBGSurfaceControl;
sp<SurfaceControl> mFGSurfaceControl;
std::unique_ptr<ScreenCapture> mCapture;
+ ui::Size mDisplaySize;
};
TEST_F(ScreenCaptureTest, SetFlagsSecureEUidSystem) {
@@ -515,18 +518,8 @@
}
TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60,
- ISurfaceComposerClient::eFXSurfaceBufferState);
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
-
- auto redLayerHandle = redLayer->getHandle();
- Transaction().reparent(redLayer, nullptr).apply();
- redLayer.clear();
- SurfaceComposerClient::Transaction().apply(true);
-
LayerCaptureArgs args;
- args.layerHandle = redLayerHandle;
+ args.layerHandle = new BBinder();
ScreenCaptureResults captureResults;
// Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
@@ -840,6 +833,33 @@
Color{expectedColor, expectedColor, expectedColor, 255}, tolerance);
}
+TEST_F(ScreenCaptureTest, CaptureOffscreen) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ mBGSurfaceControl.get()));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().show(layer).hide(mFGSurfaceControl).reparent(layer, nullptr).apply();
+
+ DisplayCaptureArgs displayCaptureArgs;
+ displayCaptureArgs.displayToken = mDisplay;
+
+ {
+ // Validate that the red layer is not on screen
+ ScreenCapture::captureDisplay(&mCapture, displayCaptureArgs);
+ mCapture->expectColor(Rect(0, 0, mDisplaySize.width, mDisplaySize.height),
+ {63, 63, 195, 255});
+ }
+
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = layer->getHandle();
+
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
+ mCapture->expectSize(32, 32);
+ mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
// 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.
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index ddaa5a1..cae7684 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -175,6 +175,11 @@
void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
+ void expectSize(uint32_t width, uint32_t height) {
+ EXPECT_EQ(width, mOutBuffer->getWidth());
+ EXPECT_EQ(height, mOutBuffer->getHeight());
+ }
+
explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
if (mOutBuffer) {
mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));