diff options
| -rw-r--r-- | libs/gui/ISurfaceComposer.cpp | 7 | ||||
| -rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 12 | ||||
| -rw-r--r-- | libs/gui/include/gui/ISurfaceComposer.h | 5 | ||||
| -rw-r--r-- | libs/gui/include/gui/SurfaceComposerClient.h | 4 | ||||
| -rw-r--r-- | libs/gui/tests/Surface_test.cpp | 4 | ||||
| -rw-r--r-- | services/surfaceflinger/ContainerLayer.cpp | 14 | ||||
| -rw-r--r-- | services/surfaceflinger/ContainerLayer.h | 10 | ||||
| -rw-r--r-- | services/surfaceflinger/Layer.cpp | 6 | ||||
| -rw-r--r-- | services/surfaceflinger/Layer.h | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/RenderArea.h | 4 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 81 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/Transaction_test.cpp | 78 |
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(); |