summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/gui/ISurfaceComposer.cpp7
-rw-r--r--libs/gui/SurfaceComposerClient.cpp12
-rw-r--r--libs/gui/include/gui/ISurfaceComposer.h5
-rw-r--r--libs/gui/include/gui/SurfaceComposerClient.h4
-rw-r--r--libs/gui/tests/Surface_test.cpp4
-rw-r--r--services/surfaceflinger/ContainerLayer.cpp14
-rw-r--r--services/surfaceflinger/ContainerLayer.h10
-rw-r--r--services/surfaceflinger/Layer.cpp6
-rw-r--r--services/surfaceflinger/Layer.h2
-rw-r--r--services/surfaceflinger/RenderArea.h4
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp81
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h2
-rw-r--r--services/surfaceflinger/tests/Transaction_test.cpp78
13 files changed, 191 insertions, 38 deletions
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 5de84ecbab..beda778396 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -132,12 +132,13 @@ public:
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
- float frameScale) {
+ float frameScale, bool childrenOnly) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(layerHandleBinder);
data.write(sourceCrop);
data.writeFloat(frameScale);
+ data.writeBool(childrenOnly);
status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
if (err != NO_ERROR) {
@@ -629,8 +630,10 @@ status_t BnSurfaceComposer::onTransact(
Rect sourceCrop(Rect::EMPTY_RECT);
data.read(sourceCrop);
float frameScale = data.readFloat();
+ bool childrenOnly = data.readBool();
- status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale);
+ status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale,
+ childrenOnly);
reply->writeInt32(res);
if (res == NO_ERROR) {
reply->write(*outBuffer);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 92a24ad933..0d7ffc3d71 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -751,7 +751,17 @@ status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect so
float frameScale, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
- status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale);
+ status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
+ false /* childrenOnly */);
+ return ret;
+}
+
+status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+ float frameScale, sp<GraphicBuffer>* outBuffer) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
+ true /* childrenOnly */);
return ret;
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e26e332589..5ab64454e5 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -173,9 +173,12 @@ public:
int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
Rotation rotation = eRotateNone) = 0;
+ /**
+ * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+ */
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
- float frameScale = 1.0) = 0;
+ float frameScale = 1.0, bool childrenOnly = false) = 0;
/* Clears the frame statistics for animations.
*
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 3fe66356bf..fe46146ff5 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -297,8 +297,10 @@ public:
uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ,
bool useIdentityTransform, uint32_t rotation,
sp<GraphicBuffer>* outBuffer);
- static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float fameScale,
+ static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float frameScale,
sp<GraphicBuffer>* outBuffer);
+ static status_t captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+ float frameScale, sp<GraphicBuffer>* outBuffer);
};
// ---------------------------------------------------------------------------
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8060b6e7c5..4fb51e1b96 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -593,8 +593,8 @@ public:
bool /*useIdentityTransform*/,
Rotation /*rotation*/) override { return NO_ERROR; }
virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
- sp<GraphicBuffer>* /*outBuffer*/,
- const Rect& /*sourceCrop*/, float /*frameScale*/) override {
+ sp<GraphicBuffer>* /*outBuffer*/, const Rect& /*sourceCrop*/,
+ float /*frameScale*/, bool /*childrenOnly*/) override {
return NO_ERROR;
}
status_t clearAnimationFrameStats() override { return NO_ERROR; }
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 2f89cc1d76..f259d93c3f 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -16,24 +16,24 @@
// #define LOG_NDEBUG 0
#undef LOG_TAG
-#define LOG_TAG "AbstractLayer"
+#define LOG_TAG "ContainerLayer"
-#include "AbstractLayer.h"
+#include "ContainerLayer.h"
namespace android {
-AbstractLayer::AbstractLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
- uint32_t w, uint32_t h, uint32_t flags)
+ContainerLayer::ContainerLayer(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags)
: Layer(flinger, client, name, w, h, flags) {
mDrawingState = mCurrentState;
}
-void AbstractLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) const {}
+void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) const {}
-bool AbstractLayer::isVisible() const {
+bool ContainerLayer::isVisible() const {
return !isHiddenByPolicy();
}
-void AbstractLayer::setPerFrameData(const sp<const DisplayDevice>&) {}
+void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&) {}
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 808ae3367d..543f60a624 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -23,13 +23,13 @@
namespace android {
-class AbstractLayer : public Layer {
+class ContainerLayer : public Layer {
public:
- AbstractLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
- uint32_t w, uint32_t h, uint32_t flags);
- virtual ~AbstractLayer() = default;
+ ContainerLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags);
+ virtual ~ContainerLayer() = default;
- const char* getTypeId() const override { return "AbstractLayer"; }
+ const char* getTypeId() const override { return "ContainerLayer"; }
void onDraw(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform) const override;
bool isVisible() const override;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 78dd40b32f..44e60edb37 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1594,6 +1594,12 @@ bool Layer::reparentChildren(const sp<IBinder>& newParentHandle) {
return true;
}
+void Layer::reparentChildrenForDrawing(const sp<Layer>& newParent) {
+ for (const sp<Layer>& child : mDrawingChildren) {
+ child->mDrawingParent = newParent;
+ }
+}
+
bool Layer::reparent(const sp<IBinder>& newParentHandle) {
if (newParentHandle == nullptr) {
return false;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ab004f2a6f..996d686371 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -287,7 +287,7 @@ public:
bool setOverrideScalingMode(int32_t overrideScalingMode);
void setInfo(uint32_t type, uint32_t appId);
bool reparentChildren(const sp<IBinder>& layer);
- bool reparentChildrenForDrawing(const sp<Layer>& layer);
+ void reparentChildrenForDrawing(const sp<Layer>& layer);
bool reparent(const sp<IBinder>& newParentHandle);
bool detachChildren();
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index fa4df8360f..940a34ce1c 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -2,6 +2,8 @@
#include "Transform.h"
+#include <functional>
+
namespace android {
class RenderArea {
@@ -22,6 +24,8 @@ public:
virtual bool needsFiltering() const = 0;
virtual Rect getSourceCrop() const = 0;
+ virtual void render(std::function<void()> drawLayers) { drawLayers(); }
+
int getReqHeight() const { return mReqHeight; };
int getReqWidth() const { return mReqWidth; };
Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cb410a14e1..38b93b110b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -61,20 +61,21 @@
#include <private/android_filesystem_config.h>
#include <private/gui/SyncFeatures.h>
+#include "BufferLayer.h"
#include "Client.h"
-#include "clz.h"
+#include "ColorLayer.h"
#include "Colorizer.h"
+#include "ContainerLayer.h"
#include "DdmConnection.h"
-#include "DisplayDevice.h"
#include "DispSync.h"
+#include "DisplayDevice.h"
#include "EventControlThread.h"
#include "EventThread.h"
#include "Layer.h"
-#include "BufferLayer.h"
#include "LayerVector.h"
-#include "ColorLayer.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
+#include "clz.h"
#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/FramebufferSurface.h"
@@ -4418,19 +4419,18 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<GraphicBuf
status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
- float frameScale) {
+ float frameScale, bool childrenOnly) {
ATRACE_CALL();
class LayerRenderArea : public RenderArea {
public:
- LayerRenderArea(const sp<Layer>& layer, const Rect crop, int32_t reqWidth,
- int32_t reqHeight)
- : RenderArea(reqHeight, reqWidth), mLayer(layer), mCrop(crop) {}
- const Transform& getTransform() const override {
- // Make the top level transform the inverse the transform and it's parent so it sets
- // the whole capture back to 0,0
- return *new Transform(mLayer->getTransform().inverse());
- }
+ LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
+ int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
+ : RenderArea(reqHeight, reqWidth),
+ mLayer(layer),
+ mCrop(crop),
+ mFlinger(flinger),
+ mChildrenOnly(childrenOnly) {}
Rect getBounds() const override {
const Layer::State& layerState(mLayer->getDrawingState());
return Rect(layerState.active.w, layerState.active.h);
@@ -4439,6 +4439,34 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
int getWidth() const override { return mLayer->getDrawingState().active.w; }
bool isSecure() const override { return false; }
bool needsFiltering() const override { return false; }
+ const Transform& getTransform() const { return mTransform; }
+
+ class ReparentForDrawing {
+ public:
+ const sp<Layer>& oldParent;
+ const sp<Layer>& newParent;
+
+ ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent)
+ : oldParent(oldParent), newParent(newParent) {
+ oldParent->reparentChildrenForDrawing(newParent);
+ }
+ ~ReparentForDrawing() { newParent->reparentChildrenForDrawing(oldParent); }
+ };
+
+ void render(std::function<void()> drawLayers) override {
+ if (!mChildrenOnly) {
+ mTransform = mLayer->getTransform().inverse();
+ drawLayers();
+ } else {
+ Rect bounds = getBounds();
+ screenshotParentLayer =
+ new ContainerLayer(mFlinger, nullptr, String8("Screenshot Parent"),
+ bounds.getWidth(), bounds.getHeight(), 0);
+
+ ReparentForDrawing reparent(mLayer, screenshotParentLayer);
+ drawLayers();
+ }
+ }
Rect getSourceCrop() const override {
if (mCrop.isEmpty()) {
@@ -4453,6 +4481,14 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
private:
const sp<Layer> mLayer;
const Rect mCrop;
+
+ // In the "childrenOnly" case we reparent the children to a screenshot
+ // layer which has no properties set and which does not draw.
+ sp<ContainerLayer> screenshotParentLayer;
+ Transform mTransform;
+
+ SurfaceFlinger* mFlinger;
+ const bool mChildrenOnly;
};
auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
@@ -4463,6 +4499,13 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
return NAME_NOT_FOUND;
}
+ const int uid = IPCThreadState::self()->getCallingUid();
+ const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+ if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
+ ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
+ return PERMISSION_DENIED;
+ }
+
Rect crop(sourceCrop);
if (sourceCrop.width() <= 0) {
crop.left = 0;
@@ -4477,12 +4520,14 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
int32_t reqWidth = crop.width() * frameScale;
int32_t reqHeight = crop.height() * frameScale;
- LayerRenderArea renderArea(parent, crop, reqWidth, reqHeight);
+ LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly);
- auto traverseLayers = [parent](const LayerVector::Visitor& visitor) {
+ auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) {
parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
if (!layer->isVisible()) {
return;
+ } else if (childrenOnly && layer == parent.get()) {
+ return;
}
visitor(layer);
});
@@ -4529,8 +4574,10 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
int fd = -1;
{
Mutex::Autolock _l(mStateLock);
- result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
- useIdentityTransform, forSystem, &fd);
+ renderArea.render([&]() {
+ result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
+ useIdentityTransform, forSystem, &fd);
+ });
}
{
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 392acaa0a6..33786e8558 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -387,7 +387,7 @@ private:
int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
ISurfaceComposer::Rotation rotation);
virtual status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
- const Rect& sourceCrop, float frameScale);
+ const Rect& sourceCrop, float frameScale, bool childrenOnly);
virtual status_t getDisplayStats(const sp<IBinder>& display,
DisplayStatInfo* stats);
virtual status_t getDisplayConfigs(const sp<IBinder>& display,
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 92c26af9eb..fd219913df 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -192,6 +192,16 @@ public:
*sc = std::make_unique<ScreenCapture>(outBuffer);
}
+ static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+ Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true));
+ *sc = std::make_unique<ScreenCapture>(outBuffer);
+ }
+
void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
@@ -2306,6 +2316,74 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
mCapture->expectChildColor(0, 0);
}
+TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child =
+ mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mFGSurfaceControl.get());
+ fillSurfaceRGBA8(child, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ // Captures mFGSurfaceControl's child
+ ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+ mCapture->checkPixel(10, 10, 0, 0, 0);
+ mCapture->expectChildColor(0, 0);
+}
+
+
+// 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.
+class ScreenCaptureChildOnlyTest : public LayerUpdateTest {
+public:
+ void SetUp() override {
+ LayerUpdateTest::SetUp();
+
+ mChild =
+ mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mFGSurfaceControl.get());
+ fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(mChild).apply(true);
+ }
+
+ void verify() {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+ ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+ mCapture->checkPixel(10, 10, 0, 0, 0);
+ mCapture->expectChildColor(0, 0);
+ }
+
+ std::unique_ptr<ScreenCapture> mCapture;
+ sp<SurfaceControl> mChild;
+};
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
+
+ SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
+
+ // Even though the parent is hidden we should still capture the child.
+ verify();
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
+
+ SurfaceComposerClient::Transaction().setCrop(mFGSurfaceControl, Rect(0, 0, 1, 1)).apply(true);
+
+ // Even though the parent is cropped out we should still capture the child.
+ verify();
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
+
+ SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2);
+
+ // We should not inherit the parent scaling.
+ verify();
+}
+
TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
auto fgHandle = mFGSurfaceControl->getHandle();