From cdf832043afeb74598d64f8689098ae75dad8731 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 7 Mar 2018 12:48:34 -0800 Subject: SurfaceFlinger: Add "Abstract" Layer type. Add an Abstract Layer type which exists only to be a parent. We will use this to more cleanly represent the various hierarchy Layers from the WM and for an upcoming screenshot rework. Bug: 72760590 Test: Existing tests pass Change-Id: Icd19ab0a467585660a95ae37b9c5dd4b8106da9d --- services/surfaceflinger/ContainerLayer.cpp | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 services/surfaceflinger/ContainerLayer.cpp (limited to 'services/surfaceflinger/ContainerLayer.cpp') diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp new file mode 100644 index 0000000000..2f89cc1d76 --- /dev/null +++ b/services/surfaceflinger/ContainerLayer.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "AbstractLayer" + +#include "AbstractLayer.h" + +namespace android { + +AbstractLayer::AbstractLayer(SurfaceFlinger* flinger, const sp& 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 {} + +bool AbstractLayer::isVisible() const { + return !isHiddenByPolicy(); +} + +void AbstractLayer::setPerFrameData(const sp&) {} + +} // namespace android -- cgit v1.2.3-59-g8ed1b From 578038fc49f83c4c8c4accdce49df404ecd6ad02 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 9 Mar 2018 12:25:24 -0800 Subject: SurfaceFlinger: Add childLayersOnly variant of capture layers. Currently captureLayers is being used to capture children of abstract buffer-less layers, for example we capture the node representing a Task. Because of animations, etc, the node may have been scaled when we want to take the screenshot, so we solved this problem with an inverse transform in LayerRenderArea. However we have parallel problems for crop, visibility, etc...It seems what we really want from captureLayers is the ability to capture all child layers while ignoring the parent imposed state as if in a parallel hierarchy. I initially considered implementing a parallel hierarchy with layer clones but it seemed much less risky for P to instead reparent the existing hierarchy to a parallel abstract parent on the server side. Bug: 72760590 Test: Existing tests pass. Quickstep works with new implementation. New transaction tests. Change-Id: Ifd2b2f9ed45351d8ed0d7f09be1cd9806ec4abe8 --- libs/gui/ISurfaceComposer.cpp | 7 +- libs/gui/SurfaceComposerClient.cpp | 12 +++- libs/gui/include/gui/ISurfaceComposer.h | 5 +- libs/gui/include/gui/SurfaceComposerClient.h | 4 +- libs/gui/tests/Surface_test.cpp | 4 +- services/surfaceflinger/ContainerLayer.cpp | 14 ++-- services/surfaceflinger/ContainerLayer.h | 10 +-- services/surfaceflinger/Layer.cpp | 6 ++ services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/RenderArea.h | 4 ++ services/surfaceflinger/SurfaceFlinger.cpp | 81 +++++++++++++++++----- services/surfaceflinger/SurfaceFlinger.h | 2 +- services/surfaceflinger/tests/Transaction_test.cpp | 78 +++++++++++++++++++++ 13 files changed, 191 insertions(+), 38 deletions(-) (limited to 'services/surfaceflinger/ContainerLayer.cpp') 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& layerHandleBinder, sp* 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& layerHandle, Rect so float frameScale, sp* outBuffer) { sp 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& layerHandle, Rect sourceCrop, + float frameScale, sp* outBuffer) { + sp 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& layerHandleBinder, sp* 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* outBuffer); - static status_t captureLayers(const sp& layerHandle, Rect sourceCrop, float fameScale, + static status_t captureLayers(const sp& layerHandle, Rect sourceCrop, float frameScale, sp* outBuffer); + static status_t captureChildLayers(const sp& layerHandle, Rect sourceCrop, + float frameScale, sp* 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& /*parentHandle*/, - sp* /*outBuffer*/, - const Rect& /*sourceCrop*/, float /*frameScale*/) override { + sp* /*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, const String8& name, - uint32_t w, uint32_t h, uint32_t flags) +ContainerLayer::ContainerLayer(SurfaceFlinger* flinger, const sp& 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&) {} +void ContainerLayer::setPerFrameData(const sp&) {} } // 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, const String8& name, - uint32_t w, uint32_t h, uint32_t flags); - virtual ~AbstractLayer() = default; + ContainerLayer(SurfaceFlinger* flinger, const sp& 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& newParentHandle) { return true; } +void Layer::reparentChildrenForDrawing(const sp& newParent) { + for (const sp& child : mDrawingChildren) { + child->mDrawingParent = newParent; + } +} + bool Layer::reparent(const sp& 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& layer); - bool reparentChildrenForDrawing(const sp& layer); + void reparentChildrenForDrawing(const sp& layer); bool reparent(const sp& 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 + namespace android { class RenderArea { @@ -22,6 +24,8 @@ public: virtual bool needsFiltering() const = 0; virtual Rect getSourceCrop() const = 0; + virtual void render(std::function 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 #include +#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& display, sp& layerHandleBinder, sp* outBuffer, const Rect& sourceCrop, - float frameScale) { + float frameScale, bool childrenOnly) { ATRACE_CALL(); class LayerRenderArea : public RenderArea { public: - LayerRenderArea(const sp& 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, 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& 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& oldParent; + const sp& newParent; + + ReparentForDrawing(const sp& oldParent, const sp& newParent) + : oldParent(oldParent), newParent(newParent) { + oldParent->reparentChildrenForDrawing(newParent); + } + ~ReparentForDrawing() { newParent->reparentChildrenForDrawing(oldParent); } + }; + + void render(std::function 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& layerHandleBinder, private: const sp 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 screenshotParentLayer; + Transform mTransform; + + SurfaceFlinger* mFlinger; + const bool mChildrenOnly; }; auto layerHandle = reinterpret_cast(layerHandleBinder.get()); @@ -4463,6 +4499,13 @@ status_t SurfaceFlinger::captureLayers(const sp& 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& 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& parentHandle, sp* outBuffer, - const Rect& sourceCrop, float frameScale); + const Rect& sourceCrop, float frameScale, bool childrenOnly); virtual status_t getDisplayStats(const sp& display, DisplayStatInfo* stats); virtual status_t getDisplayConfigs(const sp& 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(outBuffer); } + static void captureChildLayers(std::unique_ptr* sc, sp& parentHandle, + Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) { + sp sf(ComposerService::getComposerService()); + SurfaceComposerClient::Transaction().apply(true); + + sp outBuffer; + ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true)); + *sc = std::make_unique(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 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 mCapture; + sp 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(); -- cgit v1.2.3-59-g8ed1b