diff options
author | 2017-09-20 12:02:26 -0700 | |
---|---|---|
committer | 2017-10-26 17:39:24 -0700 | |
commit | a76b271f0e14325fa0ebb98e1cac0a15adfea1cb (patch) | |
tree | e13158ef19eed46d32d6a0984da3fe1645206fe6 | |
parent | cd8ad33289b74243e21a776a5a9170c845d990c4 (diff) |
Add captureLayers function to capture a layer and its children.
The captureLayers function gets a root layer as its argument.
It will capture the content for that layer and its descendants. The
capture will set the root layer's transform back to (0, 0).
Test: Transaction_test ScreenCaptureTest
Change-Id: I84fb66a65cd91434cddc99506b1924cf9f950935
-rw-r--r-- | libs/gui/ISurfaceComposer.cpp | 24 | ||||
-rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 9 | ||||
-rw-r--r-- | libs/gui/include/gui/ISurfaceComposer.h | 5 | ||||
-rw-r--r-- | libs/gui/include/gui/SurfaceComposerClient.h | 3 | ||||
-rw-r--r-- | libs/gui/tests/Surface_test.cpp | 5 | ||||
-rw-r--r-- | services/surfaceflinger/Android.mk | 1 | ||||
-rw-r--r-- | services/surfaceflinger/ColorLayer.cpp | 7 | ||||
-rw-r--r-- | services/surfaceflinger/ColorLayer.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.h | 31 | ||||
-rwxr-xr-x | services/surfaceflinger/Layer.cpp | 85 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.h | 23 | ||||
-rw-r--r-- | services/surfaceflinger/RenderArea.cpp | 34 | ||||
-rw-r--r-- | services/surfaceflinger/RenderArea.h | 40 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 326 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 43 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger_hwc1.cpp | 326 | ||||
-rw-r--r-- | services/surfaceflinger/Transform.cpp | 19 | ||||
-rw-r--r-- | services/surfaceflinger/Transform.h | 4 | ||||
-rw-r--r-- | services/surfaceflinger/tests/Transaction_test.cpp | 159 |
19 files changed, 760 insertions, 386 deletions
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 96771257c1..973302c226 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -122,6 +122,18 @@ public: return reply.readInt32(); } + virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder, + const sp<IGraphicBufferProducer>& producer, + ISurfaceComposer::Rotation rotation) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(layerHandleBinder); + data.writeStrongBinder(IInterface::asBinder(producer)); + data.writeInt32(static_cast<int32_t>(rotation)); + remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); + return reply.readInt32(); + } + virtual bool authenticateSurfaceTexture( const sp<IGraphicBufferProducer>& bufferProducer) const { @@ -588,6 +600,18 @@ status_t BnSurfaceComposer::onTransact( reply->writeInt32(res); return NO_ERROR; } + case CAPTURE_LAYERS: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> layerHandleBinder = data.readStrongBinder(); + sp<IGraphicBufferProducer> producer = + interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); + int32_t rotation = data.readInt32(); + + status_t res = captureLayers(layerHandleBinder, producer, + static_cast<ISurfaceComposer::Rotation>(rotation)); + reply->writeInt32(res); + return NO_ERROR; + } case AUTHENTICATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IGraphicBufferProducer> bufferProducer = diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 40e319e28a..15c4c9a880 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -731,6 +731,15 @@ status_t ScreenshotClient::captureToBuffer(const sp<IBinder>& display, return ret; } +status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, + const sp<IGraphicBufferProducer>& producer, + uint32_t rotation) { + sp<ISurfaceComposer> s(ComposerService::getComposerService()); + if (s == NULL) return NO_INIT; + return s->captureLayers(layerHandle, producer, + static_cast<ISurfaceComposer::Rotation>(rotation)); +} + ScreenshotClient::ScreenshotClient() : mHaveBuffer(false) { memset(&mBuffer, 0, sizeof(mBuffer)); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index b2267426a8..13e7473d54 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -174,6 +174,10 @@ public: bool useIdentityTransform, Rotation rotation = eRotateNone) = 0; + virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder, + const sp<IGraphicBufferProducer>& producer, + Rotation rotation = eRotateNone) = 0; + /* Clears the frame statistics for animations. * * Requires the ACCESS_SURFACE_FLINGER permission. @@ -226,6 +230,7 @@ public: SET_ACTIVE_CONFIG, CONNECT_DISPLAY, CAPTURE_SCREEN, + CAPTURE_LAYERS, CLEAR_ANIMATION_FRAME_STATS, GET_ANIMATION_FRAME_STATS, SET_POWER_MODE, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 00d593638d..d63dafea41 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -297,6 +297,9 @@ public: bool useIdentityTransform, uint32_t rotation, sp<GraphicBuffer>* outbuffer); + static status_t captureLayers(const sp<IBinder>& layerHandle, + const sp<IGraphicBufferProducer>& producer, uint32_t rotation); + private: mutable sp<CpuConsumer> mCpuConsumer; mutable sp<IGraphicBufferProducer> mProducer; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 572760e77d..660680bf9e 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -529,6 +529,11 @@ public: int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/, bool /*useIdentityTransform*/, Rotation /*rotation*/) override { return NO_ERROR; } + virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/, + const sp<IGraphicBufferProducer>& /*producer*/, + ISurfaceComposer::Rotation /*rotation*/) override { + return NO_ERROR; + } status_t clearAnimationFrameStats() override { return NO_ERROR; } status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { return NO_ERROR; diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index d8152e08cc..d9bca04b0b 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -40,6 +40,7 @@ LOCAL_SRC_FILES := \ RenderEngine/Texture.cpp \ RenderEngine/GLES20RenderEngine.cpp \ LayerProtoHelper.cpp \ + RenderArea.cpp \ LOCAL_MODULE := libsurfaceflinger LOCAL_C_INCLUDES := \ diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp index 6923782b27..32526dd29b 100644 --- a/services/surfaceflinger/ColorLayer.cpp +++ b/services/surfaceflinger/ColorLayer.cpp @@ -40,13 +40,12 @@ ColorLayer::ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client, : Layer(flinger, client, name, w, h, flags) { } -void ColorLayer::onDraw(const sp<const DisplayDevice>& hw, - const Region& /* clip */, bool useIdentityTransform) const -{ +void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */, + bool useIdentityTransform) const { const State& s(getDrawingState()); if (s.color.a>0) { Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2); - computeGeometry(hw, mesh, useIdentityTransform); + computeGeometry(renderArea, mesh, useIdentityTransform); RenderEngine& engine(mFlinger->getRenderEngine()); engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */, true /* disableTexture */, s.color); diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h index ac3e2a95dc..cdf3eca60a 100644 --- a/services/surfaceflinger/ColorLayer.h +++ b/services/surfaceflinger/ColorLayer.h @@ -34,7 +34,7 @@ public: virtual ~ColorLayer() = default; virtual const char* getTypeId() const { return "ColorLayer"; } - virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip, + virtual void onDraw(const RenderArea& renderArea, const Region& clip, bool useIdentityTransform) const; virtual bool isOpaque(const Layer::State&) const { return false; } virtual bool isSecure() const { return false; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 8636e2af79..49fef5805f 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -37,7 +37,9 @@ #include <utils/String8.h> #include <utils/Timers.h> +#include <gui/ISurfaceComposer.h> #include <hardware/hwcomposer_defs.h> +#include "RenderArea.h" #ifdef USE_HWC2 #include <memory> @@ -300,6 +302,35 @@ struct DisplayDeviceState { bool isSecure = false; }; +class DisplayRenderArea : public RenderArea { +public: + DisplayRenderArea(const sp<const DisplayDevice> device, + ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone) + : DisplayRenderArea(device, device->getBounds(), device->getHeight(), device->getWidth(), + rotation) {} + DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqHeight, + uint32_t reqWidth, ISurfaceComposer::Rotation rotation) + : RenderArea(reqHeight, reqWidth, rotation), mDevice(device), mSourceCrop(sourceCrop) {} + + const Transform& getTransform() const override { return mDevice->getTransform(); } + Rect getBounds() const override { return mDevice->getBounds(); } + int getHeight() const override { return mDevice->getHeight(); } + int getWidth() const override { return mDevice->getWidth(); } + bool isSecure() const override { return mDevice->isSecure(); } + bool needsFiltering() const override { return mDevice->needsFiltering(); } + Rect getSourceCrop() const override { return mSourceCrop; } +#ifdef USE_HWC2 + bool getWideColorSupport() const override { return mDevice->getWideColorSupport(); } + android_color_mode_t getActiveColorMode() const override { + return mDevice->getActiveColorMode(); + } +#endif + +private: + const sp<const DisplayDevice> mDevice; + const Rect mSourceCrop; +}; + }; // namespace android #endif // ANDROID_DISPLAY_DEVICE_H diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 27739ce074..56328c9b3d 100755 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1063,17 +1063,16 @@ Rect Layer::getPosition( // drawing... // --------------------------------------------------------------------------- -void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) const { - onDraw(hw, clip, false); +void Layer::draw(const RenderArea& renderArea, const Region& clip) const { + onDraw(renderArea, clip, false); } -void Layer::draw(const sp<const DisplayDevice>& hw, - bool useIdentityTransform) const { - onDraw(hw, Region(hw->bounds()), useIdentityTransform); +void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) const { + onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform); } -void Layer::draw(const sp<const DisplayDevice>& hw) const { - onDraw(hw, Region(hw->bounds()), false); +void Layer::draw(const RenderArea& renderArea) const { + onDraw(renderArea, Region(renderArea.getBounds()), false); } static constexpr mat4 inverseOrientation(uint32_t transform) { @@ -1097,7 +1096,7 @@ static constexpr mat4 inverseOrientation(uint32_t transform) { /* * onDraw will draw the current layer onto the presentable buffer */ -void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip, +void Layer::onDraw(const RenderArea& renderArea, const Region& clip, bool useIdentityTransform) const { ATRACE_CALL(); @@ -1119,12 +1118,12 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip, finished = true; return; } - under.orSelf( hw->getTransform().transform(layer->visibleRegion) ); + under.orSelf(renderArea.getTransform().transform(layer->visibleRegion)); }); // if not everything below us is covered, we plug the holes! Region holes(clip.subtract(under)); if (!holes.isEmpty()) { - clearWithOpenGL(hw, 0, 0, 0, 1); + clearWithOpenGL(renderArea, 0, 0, 0, 1); } return; } @@ -1138,13 +1137,13 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip, // is probably going to have something visibly wrong. } - bool blackOutLayer = isProtected() || (isSecure() && !hw->isSecure()); + bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure()); RenderEngine& engine(mFlinger->getRenderEngine()); if (!blackOutLayer) { // TODO: we could be more subtle with isFixedSize() - const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize(); + const bool useFiltering = getFiltering() || needsFiltering(renderArea) || isFixedSize(); // Query the texture matrix given our current filtering mode. float textureMatrix[16]; @@ -1190,31 +1189,29 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip, } else { engine.setupLayerBlackedOut(); } - drawWithOpenGL(hw, useIdentityTransform); + drawWithOpenGL(renderArea, useIdentityTransform); engine.disableTexturing(); } -void Layer::clearWithOpenGL(const sp<const DisplayDevice>& hw, +void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue, float alpha) const { RenderEngine& engine(mFlinger->getRenderEngine()); - computeGeometry(hw, mMesh, false); + computeGeometry(renderArea, mMesh, false); engine.setupFillWithColor(red, green, blue, alpha); engine.drawMesh(mMesh); } -void Layer::clearWithOpenGL( - const sp<const DisplayDevice>& hw) const { - clearWithOpenGL(hw, 0,0,0,0); +void Layer::clearWithOpenGL(const RenderArea& renderArea) const { + clearWithOpenGL(renderArea, 0,0,0,0); } -void Layer::drawWithOpenGL(const sp<const DisplayDevice>& hw, - bool useIdentityTransform) const { +void Layer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const { const State& s(getDrawingState()); - computeGeometry(hw, mMesh, useIdentityTransform); + computeGeometry(renderArea, mMesh, useIdentityTransform); /* * NOTE: the way we compute the texture coordinates here produces @@ -1440,12 +1437,11 @@ static void boundPoint(vec2* point, const Rect& crop) { } } -void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, - bool useIdentityTransform) const -{ +void Layer::computeGeometry(const RenderArea& renderArea, Mesh& mesh, + bool useIdentityTransform) const { const Layer::State& s(getDrawingState()); - const Transform hwTransform(hw->getTransform()); - const uint32_t hw_h = hw->getHeight(); + const Transform renderAreaTransform(renderArea.getTransform()); + const uint32_t height = renderArea.getHeight(); Rect win = computeBounds(); vec2 lt = vec2(win.left, win.top); @@ -1469,12 +1465,12 @@ void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, } Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - position[0] = hwTransform.transform(lt); - position[1] = hwTransform.transform(lb); - position[2] = hwTransform.transform(rb); - position[3] = hwTransform.transform(rt); + position[0] = renderAreaTransform.transform(lt); + position[1] = renderAreaTransform.transform(lb); + position[2] = renderAreaTransform.transform(rb); + position[3] = renderAreaTransform.transform(rt); for (size_t i=0 ; i<4 ; i++) { - position[i].y = hw_h - position[i].y; + position[i].y = height - position[i].y; } } @@ -1512,8 +1508,8 @@ bool Layer::isCropped() const { return !mCurrentCrop.isEmpty(); } -bool Layer::needsFiltering(const sp<const DisplayDevice>& hw) const { - return mNeedsFiltering || hw->needsFiltering(); +bool Layer::needsFiltering(const RenderArea& renderArea) const { + return mNeedsFiltering || renderArea.needsFiltering(); } void Layer::setVisibleRegion(const Region& visibleRegion) { @@ -2773,6 +2769,29 @@ void Layer::traverseInReverseZOrder(LayerVector::StateSet stateSet, } } +/** + * Traverse only children in z order, ignoring relative layers. + */ +void Layer::traverseChildrenInZOrder(LayerVector::StateSet stateSet, + const LayerVector::Visitor& visitor) { + const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; + const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren; + + size_t i = 0; + for (; i < children.size(); i++) { + const auto& relative = children[i]; + if (relative->getZ() >= 0) { + break; + } + relative->traverseChildrenInZOrder(stateSet, visitor); + } + visitor(this); + for (; i < children.size(); i++) { + const auto& relative = children[i]; + relative->traverseChildrenInZOrder(stateSet, visitor); + } +} + Transform Layer::getTransform() const { Transform t; const auto& p = mDrawingParent.promote(); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 06c4863ce2..d75e175f5a 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -50,6 +50,7 @@ #include "RenderEngine/Mesh.h" #include "RenderEngine/Texture.h" #include <layerproto/LayerProtoHeader.h> +#include "RenderArea.h" #include <math/vec4.h> @@ -255,8 +256,7 @@ public: return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay); } - void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, - bool useIdentityTransform) const; + void computeGeometry(const RenderArea& renderArea, Mesh& mesh, bool useIdentityTransform) const; Rect computeBounds(const Region& activeTransparentRegion) const; Rect computeBounds() const; @@ -312,7 +312,7 @@ protected: /* * onDraw - draws the surface. */ - virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip, + virtual void onDraw(const RenderArea& renderArea, const Region& clip, bool useIdentityTransform) const; public: @@ -379,9 +379,9 @@ public: * draw - performs some global clipping optimizations * and calls onDraw(). */ - void draw(const sp<const DisplayDevice>& hw, const Region& clip) const; - void draw(const sp<const DisplayDevice>& hw, bool useIdentityTransform) const; - void draw(const sp<const DisplayDevice>& hw) const; + void draw(const RenderArea& renderArea, const Region& clip) const; + void draw(const RenderArea& renderArea, bool useIdentityTransform) const; + void draw(const RenderArea& renderArea) const; /* * doTransaction - process the transaction. This is a good place to figure @@ -472,7 +472,7 @@ public: #endif // ----------------------------------------------------------------------- - void clearWithOpenGL(const sp<const DisplayDevice>& hw) const; + void clearWithOpenGL(const RenderArea& renderArea) const; void setFiltering(bool filtering); bool getFiltering() const; @@ -516,6 +516,9 @@ public: const LayerVector::Visitor& visitor); void traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor); + void traverseChildrenInZOrder(LayerVector::StateSet stateSet, + const LayerVector::Visitor& visitor); + size_t getChildrenCount() const; void addChild(const sp<Layer>& layer); // Returns index if removed, or negative value otherwise @@ -569,7 +572,7 @@ private: void commitTransaction(const State& stateToCommit); // needsLinearFiltering - true if this surface's state requires filtering - bool needsFiltering(const sp<const DisplayDevice>& hw) const; + bool needsFiltering(const RenderArea& renderArea) const; uint32_t getEffectiveUsage(uint32_t usage) const; @@ -582,9 +585,9 @@ private: static bool getOpacityForFormat(uint32_t format); // drawing - void clearWithOpenGL(const sp<const DisplayDevice>& hw, + void clearWithOpenGL(const RenderArea& renderArea, float r, float g, float b, float alpha) const; - void drawWithOpenGL(const sp<const DisplayDevice>& hw, + void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const; // Temporary - Used only for LEGACY camera mode. diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp new file mode 100644 index 0000000000..6225df134d --- /dev/null +++ b/services/surfaceflinger/RenderArea.cpp @@ -0,0 +1,34 @@ +#include "RenderArea.h" + +namespace android { + +/* + * Checks that the requested width and height are valid and updates them to the render area + * dimensions if they are set to 0 + */ +status_t RenderArea::updateDimensions() { + // get screen geometry + + uint32_t width = getWidth(); + uint32_t height = getHeight(); + + if (mRotationFlags & Transform::ROT_90) { + std::swap(width, height); + } + + if ((mReqWidth > width) || (mReqHeight > height)) { + ALOGE("size mismatch (%d, %d) > (%d, %d)", mReqWidth, mReqHeight, width, height); + return BAD_VALUE; + } + + if (mReqWidth == 0) { + mReqWidth = width; + } + if (mReqHeight == 0) { + mReqHeight = height; + } + + return NO_ERROR; +} + +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h new file mode 100644 index 0000000000..faf1ec64f8 --- /dev/null +++ b/services/surfaceflinger/RenderArea.h @@ -0,0 +1,40 @@ +#pragma once + +#include "Transform.h" + +namespace android { + +class RenderArea { +public: + RenderArea(uint32_t reqHeight, uint32_t reqWidth, ISurfaceComposer::Rotation rotation) + : mReqHeight(reqHeight), mReqWidth(reqWidth) { + mRotationFlags = Transform::fromRotation(rotation); + } + + virtual ~RenderArea() = default; + + virtual const Transform& getTransform() const = 0; + virtual Rect getBounds() const = 0; + virtual int getHeight() const = 0; + virtual int getWidth() const = 0; + virtual bool isSecure() const = 0; + virtual bool needsFiltering() const = 0; + virtual Rect getSourceCrop() const = 0; + + int getReqHeight() const { return mReqHeight; }; + int getReqWidth() const { return mReqWidth; }; + Transform::orientation_flags getRotationFlags() const { return mRotationFlags; }; +#ifdef USE_HWC2 + virtual bool getWideColorSupport() const = 0; + virtual android_color_mode_t getActiveColorMode() const = 0; +#endif + + status_t updateDimensions(); + +private: + uint32_t mReqHeight; + uint32_t mReqWidth; + Transform::orientation_flags mRotationFlags; +}; + +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 05c76fce46..fe9409b35e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2650,6 +2650,7 @@ bool SurfaceFlinger::doComposeSurfaces( { ALOGV("doComposeSurfaces"); + const DisplayRenderArea renderArea(displayDevice); const auto hwcId = displayDevice->getHwcDisplayId(); mat4 oldColorMatrix; @@ -2759,12 +2760,12 @@ bool SurfaceFlinger::doComposeSurfaces( && hasClientComposition) { // never clear the very first layer since we're // guaranteed the FB is already cleared - layer->clearWithOpenGL(displayDevice); + layer->clearWithOpenGL(renderArea); } break; } case HWC2::Composition::Client: { - layer->draw(displayDevice, clip); + layer->draw(renderArea, clip); break; } default: @@ -2781,7 +2782,7 @@ bool SurfaceFlinger::doComposeSurfaces( const Region clip(dirty.intersect( displayTransform.transform(layer->visibleRegion))); if (!clip.isEmpty()) { - layer->draw(displayDevice, clip); + layer->draw(renderArea, clip); } } } @@ -4029,6 +4030,17 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } break; } + case CAPTURE_LAYERS: { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + break; + } } return OK; } @@ -4228,35 +4240,6 @@ void SurfaceFlinger::repaintEverything() { repaintEverythingLocked(); } -// Checks that the requested width and height are valid and updates them to the display dimensions -// if they are set to 0 -static status_t updateDimensionsLocked(const sp<const DisplayDevice>& displayDevice, - Transform::orientation_flags rotation, - uint32_t* requestedWidth, uint32_t* requestedHeight) { - // get screen geometry - uint32_t displayWidth = displayDevice->getWidth(); - uint32_t displayHeight = displayDevice->getHeight(); - - if (rotation & Transform::ROT_90) { - std::swap(displayWidth, displayHeight); - } - - if ((*requestedWidth > displayWidth) || (*requestedHeight > displayHeight)) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", - *requestedWidth, *requestedHeight, displayWidth, displayHeight); - return BAD_VALUE; - } - - if (*requestedWidth == 0) { - *requestedWidth = displayWidth; - } - if (*requestedHeight == 0) { - *requestedHeight = displayHeight; - } - - return NO_ERROR; -} - // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope class WindowDisconnector { public: @@ -4305,50 +4288,86 @@ static status_t getWindowBuffer(ANativeWindow* window, uint32_t requestedWidth, } status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { + const sp<IGraphicBufferProducer>& producer, Rect sourceCrop, + uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ, + int32_t maxLayerZ, bool useIdentityTransform, + ISurfaceComposer::Rotation rotation) { ATRACE_CALL(); - if (CC_UNLIKELY(display == 0)) - return BAD_VALUE; + if (CC_UNLIKELY(display == 0)) return BAD_VALUE; + + const sp<const DisplayDevice> device(getDisplayDeviceLocked(display)); + DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation); + + auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this, + device, minLayerZ, maxLayerZ, std::placeholders::_1); + return captureScreenCommon(renderArea, traverseLayers, producer, useIdentityTransform); +} + +status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder, + const sp<IGraphicBufferProducer>& producer, + ISurfaceComposer::Rotation rotation) { + ATRACE_CALL(); + + class LayerRenderArea : public RenderArea { + public: + LayerRenderArea(const sp<Layer>& layer, ISurfaceComposer::Rotation rotation) + : RenderArea(layer->getCurrentState().active.h, layer->getCurrentState().active.w, + rotation), + mLayer(layer) {} + 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()); + } + Rect getBounds() const override { + const Layer::State& layerState(mLayer->getDrawingState()); + return Rect(layerState.active.w, layerState.active.h); + } + int getHeight() const override { return mLayer->getDrawingState().active.h; } + int getWidth() const override { return mLayer->getDrawingState().active.w; } + bool isSecure() const override { return false; } + bool needsFiltering() const override { return false; } + + Rect getSourceCrop() const override { return getBounds(); } + bool getWideColorSupport() const override { return false; } + android_color_mode_t getActiveColorMode() const override { return HAL_COLOR_MODE_NATIVE; } + + private: + const sp<Layer>& mLayer; + }; + + auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get()); + auto parent = layerHandle->owner.promote(); + + LayerRenderArea renderArea(parent, rotation); + auto traverseLayers = [parent](const LayerVector::Visitor& visitor) { + parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { + if (!layer->isVisible()) { + return; + } + visitor(layer); + }); + }; + return captureScreenCommon(renderArea, traverseLayers, producer, false); +} + +status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + const sp<IGraphicBufferProducer>& producer, + bool useIdentityTransform) { + ATRACE_CALL(); if (CC_UNLIKELY(producer == 0)) return BAD_VALUE; + renderArea.updateDimensions(); + // if we have secure windows on this display, never allow the screen capture // unless the producer interface is local (i.e.: we can take a screenshot for // ourselves). bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder(); - // Convert to surfaceflinger's internal rotation type. - Transform::orientation_flags rotationFlags; - switch (rotation) { - case ISurfaceComposer::eRotateNone: - rotationFlags = Transform::ROT_0; - break; - case ISurfaceComposer::eRotate90: - rotationFlags = Transform::ROT_90; - break; - case ISurfaceComposer::eRotate180: - rotationFlags = Transform::ROT_180; - break; - case ISurfaceComposer::eRotate270: - rotationFlags = Transform::ROT_270; - break; - default: - rotationFlags = Transform::ROT_0; - ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation); - break; - } - - { // Autolock scope - Mutex::Autolock lock(mStateLock); - sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display)); - updateDimensionsLocked(displayDevice, rotationFlags, &reqWidth, &reqHeight); - } - // create a surface (because we're a producer, and we need to // dequeue/queue a buffer) sp<Surface> surface = new Surface(producer, false); @@ -4369,9 +4388,9 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL); ANativeWindowBuffer* buffer = nullptr; - result = getWindowBuffer(window, reqWidth, reqHeight, - hasWideColorDisplay && !mForceNativeColorMode, - getRenderEngine().usesWideColor(), &buffer); + result = getWindowBuffer(window, renderArea.getReqWidth(), renderArea.getReqHeight(), + hasWideColorDisplay && !mForceNativeColorMode, + getRenderEngine().usesWideColor(), &buffer); if (result != NO_ERROR) { return result; } @@ -4399,10 +4418,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, int fd = -1; { Mutex::Autolock _l(mStateLock); - sp<const DisplayDevice> device(getDisplayDeviceLocked(display)); - result = captureScreenImplLocked(device, buffer, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, - rotationFlags, isLocalScreenshot, &fd); + result = captureScreenImplLocked(renderArea, traverseLayers, buffer, + useIdentityTransform, isLocalScreenshot, &fd); } { @@ -4431,84 +4448,66 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, // queueBuffer takes ownership of syncFd result = window->queueBuffer(window, buffer, syncFd); } - return result; } - -void SurfaceFlinger::renderScreenImplLocked( - const sp<const DisplayDevice>& hw, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation) -{ +void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, bool yswap, + bool useIdentityTransform) { ATRACE_CALL(); + RenderEngine& engine(getRenderEngine()); // get screen geometry - const int32_t hw_w = hw->getWidth(); - const int32_t hw_h = hw->getHeight(); - const bool filtering = static_cast<int32_t>(reqWidth) != hw_w || - static_cast<int32_t>(reqHeight) != hw_h; + const auto raWidth = renderArea.getWidth(); + const auto raHeight = renderArea.getHeight(); + + const auto reqWidth = renderArea.getReqWidth(); + const auto reqHeight = renderArea.getReqHeight(); + Rect sourceCrop = renderArea.getSourceCrop(); + + const bool filtering = static_cast<int32_t>(reqWidth) != raWidth || + static_cast<int32_t>(reqHeight) != raHeight; // if a default or invalid sourceCrop is passed in, set reasonable values - if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || - !sourceCrop.isValid()) { + if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) { sourceCrop.setLeftTop(Point(0, 0)); - sourceCrop.setRightBottom(Point(hw_w, hw_h)); + sourceCrop.setRightBottom(Point(raWidth, raHeight)); } // ensure that sourceCrop is inside screen if (sourceCrop.left < 0) { ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left); } - if (sourceCrop.right > hw_w) { - ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w); + if (sourceCrop.right > raWidth) { + ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth); } if (sourceCrop.top < 0) { ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top); } - if (sourceCrop.bottom > hw_h) { - ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h); + if (sourceCrop.bottom > raHeight) { + ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight); } -#ifdef USE_HWC2 - engine.setWideColor(hw->getWideColorSupport() && !mForceNativeColorMode); - engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE : hw->getActiveColorMode()); -#endif + engine.setWideColor(renderArea.getWideColorSupport() && !mForceNativeColorMode); + engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE : renderArea.getActiveColorMode()); // make sure to clear all GL error flags engine.checkErrors(); // set-up our viewport - engine.setViewportAndProjection( - reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation); + engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, raHeight, yswap, + renderArea.getRotationFlags()); engine.disableTexturing(); // redraw the screen entirely... engine.clearWithColor(0, 0, 0, 1); - // We loop through the first level of layers without traversing, - // as we need to interpret min/max layer Z in the top level Z space. - for (const auto& layer : mDrawingState.layersSortedByZ) { - if (!layer->belongsToDisplay(hw->getLayerStack(), false)) { - continue; - } - const Layer::State& state(layer->getDrawingState()); - if (state.z < minLayerZ || state.z > maxLayerZ) { - continue; - } - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - if (!layer->isVisible()) { - return; - } - if (filtering) layer->setFiltering(true); - layer->draw(hw, useIdentityTransform); - if (filtering) layer->setFiltering(false); - }); - } - - hw->setViewportAndProjection(); + traverseLayers([&](Layer* layer) { + if (filtering) layer->setFiltering(true); + layer->draw(renderArea, useIdentityTransform); + if (filtering) layer->setFiltering(false); + }); } // A simple RAII class that holds an EGLImage and destroys it either: @@ -4531,27 +4530,18 @@ private: EGLImageKHR mImage; }; -status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& hw, - ANativeWindowBuffer* buffer, Rect sourceCrop, - uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - Transform::orientation_flags rotation, - bool isLocalScreenshot, int* outSyncFd) { +status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + ANativeWindowBuffer* buffer, + bool useIdentityTransform, bool isLocalScreenshot, + int* outSyncFd) { ATRACE_CALL(); bool secureLayerIsVisible = false; - for (const auto& layer : mDrawingState.layersSortedByZ) { - const Layer::State& state(layer->getDrawingState()); - if (!layer->belongsToDisplay(hw->getLayerStack(), false) || - (state.z < minLayerZ || state.z > maxLayerZ)) { - continue; - } - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) { - secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && - layer->isSecure()); - }); - } + + traverseLayers([&](Layer* layer) { + secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && layer->isSecure()); + }); if (!isLocalScreenshot && secureLayerIsVisible) { ALOGW("FB is protected: PERMISSION_DENIED"); @@ -4582,9 +4572,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& // via an FBO, which means we didn't have to create // an EGLSurface and therefore we're not // dependent on the context's EGLConfig. - renderScreenImplLocked( - hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true, - useIdentityTransform, rotation); + renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform); // Attempt to create a sync khr object that can produce a sync point. If that // isn't available, create a non-dupable sync object in the fallback path and @@ -4625,46 +4613,40 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& *outSyncFd = syncFd; if (DEBUG_SCREENSHOTS) { + const auto reqWidth = renderArea.getReqWidth(); + const auto reqHeight = renderArea.getReqHeight(); + uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); - checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, - hw, minLayerZ, maxLayerZ); + checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, traverseLayers); delete [] pixels; } // destroy our image imageHolder.destroy(); - return NO_ERROR; } void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, - const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) { + TraverseLayersFunction traverseLayers) { if (DEBUG_SCREENSHOTS) { - for (size_t y=0 ; y<h ; y++) { - uint32_t const * p = (uint32_t const *)vaddr + y*s; - for (size_t x=0 ; x<w ; x++) { + for (size_t y = 0; y < h; y++) { + uint32_t const* p = (uint32_t const*)vaddr + y * s; + for (size_t x = 0; x < w; x++) { if (p[x] != 0xFF000000) return; } } - ALOGE("*** we just took a black screenshot ***\n" - "requested minz=%d, maxz=%d, layerStack=%d", - minLayerZ, maxLayerZ, hw->getLayerStack()); + ALOGE("*** we just took a black screenshot ***"); size_t i = 0; - for (const auto& layer : mDrawingState.layersSortedByZ) { + traverseLayers([&](Layer* layer) { const Layer::State& state(layer->getDrawingState()); - if (layer->belongsToDisplay(hw->getLayerStack(), false) && state.z >= minLayerZ && - state.z <= maxLayerZ) { - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f", - layer->isVisible() ? '+' : '-', - i, layer->getName().string(), layer->getLayerStack(), state.z, - layer->isVisible(), state.flags, static_cast<float>(state.color.a)); - i++; - }); - } - } + ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f", + layer->isVisible() ? '+' : '-', i, layer->getName().string(), + layer->getLayerStack(), state.z, layer->isVisible(), state.flags, + static_cast<float>(state.color.a)); + i++; + }); } } @@ -4678,6 +4660,28 @@ void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& layersSortedByZ.traverseInReverseZOrder(stateSet, visitor); } +void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw, int32_t minLayerZ, + int32_t maxLayerZ, + const LayerVector::Visitor& visitor) { + // We loop through the first level of layers without traversing, + // as we need to interpret min/max layer Z in the top level Z space. + for (const auto& layer : mDrawingState.layersSortedByZ) { + if (!layer->belongsToDisplay(hw->getLayerStack(), false)) { + continue; + } + const Layer::State& state(layer->getDrawingState()); + if (state.z < minLayerZ || state.z > maxLayerZ) { + continue; + } + layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { + if (!layer->isVisible()) { + return; + } + visitor(layer); + }); + } +} + }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index bd98c8f0e0..9975de9252 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -77,6 +77,7 @@ #include <string> #include <thread> #include <utility> +#include "RenderArea.h" #include <layerproto/LayerProtoHeader.h> @@ -97,6 +98,8 @@ class EventControlThread; class VSyncSource; class InjectVSyncSource; +typedef std::function<void(const LayerVector::Visitor&)> TraverseLayersFunction; + namespace dvr { class VrFlinger; } // namespace dvr @@ -303,6 +306,9 @@ private: Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, ISurfaceComposer::Rotation rotation); + virtual status_t captureLayers(const sp<IBinder>& parentHandle, + const sp<IGraphicBufferProducer>& producer, + ISurfaceComposer::Rotation rotation); virtual status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats); virtual status_t getDisplayConfigs(const sp<IBinder>& display, @@ -448,28 +454,26 @@ private: void startBootAnim(); - void renderScreenImplLocked( - const sp<const DisplayDevice>& hw, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation); + void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, + bool yswap, bool useIdentityTransform); + + status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, + const sp<IGraphicBufferProducer>& producer, + bool useIdentityTransform); #ifdef USE_HWC2 - status_t captureScreenImplLocked(const sp<const DisplayDevice>& device, - ANativeWindowBuffer* buffer, Rect sourceCrop, - uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ, - int32_t maxLayerZ, bool useIdentityTransform, - Transform::orientation_flags rotation, bool isLocalScreenshot, - int* outSyncFd); + status_t captureScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + ANativeWindowBuffer* buffer, bool useIdentityTransform, + bool isLocalScreenshot, int* outSyncFd); #else - status_t captureScreenImplLocked( - const sp<const DisplayDevice>& hw, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, Transform::orientation_flags rotation, - bool isLocalScreenshot); + status_t captureScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + const sp<IGraphicBufferProducer>& producer, + bool useIdentityTransform, bool isLocalScreenshot); #endif + void traverseLayersInDisplay(const sp<const DisplayDevice>& display, int32_t minLayerZ, + int32_t maxLayerZ, const LayerVector::Visitor& visitor); sp<StartPropertySetThread> mStartPropertySetThread = nullptr; @@ -613,8 +617,7 @@ private: bool startDdmConnection(); void appendSfConfigString(String8& result) const; void checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, - const sp<const DisplayDevice>& hw, - int32_t minLayerZ, int32_t maxLayerZ); + TraverseLayersFunction traverseLayers); void logFrameStats(); diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index ed7641fe99..8c530e0f61 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -2212,6 +2212,8 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty) { + DisplayRenderArea renderArea(hw); + RenderEngine& engine(getRenderEngine()); const int32_t id = hw->getHwcDisplayId(); HWComposer& hwc(getHwComposer()); @@ -2303,12 +2305,12 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const && hasGlesComposition) { // never clear the very first layer since we're // guaranteed the FB is already cleared - layer->clearWithOpenGL(hw); + layer->clearWithOpenGL(renderArea); } break; } case HWC_FRAMEBUFFER: { - layer->draw(hw, clip); + layer->draw(renderArea, clip); break; } case HWC_FRAMEBUFFER_TARGET: { @@ -2328,7 +2330,7 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const const Region clip(dirty.intersect( tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { - layer->draw(hw, clip); + layer->draw(renderArea, clip); } } } @@ -3493,6 +3495,18 @@ status_t SurfaceFlinger::onTransact( } break; } + case CAPTURE_LAYERS: + { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + break; + } } status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); @@ -3766,16 +3780,72 @@ public: } }; - status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { - + const sp<IGraphicBufferProducer>& producer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { + ATRACE_CALL(); if (CC_UNLIKELY(display == 0)) return BAD_VALUE; + const sp<const DisplayDevice> device(getDisplayDeviceLocked(display)); + DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation); + + auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this, + device, minLayerZ, maxLayerZ, std::placeholders::_1); + return captureScreenCommon(renderArea, traverseLayers, producer, useIdentityTransform); +} + +status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder, + const sp<IGraphicBufferProducer>& producer, + ISurfaceComposer::Rotation rotation) { + ATRACE_CALL(); + class LayerRenderArea : public RenderArea { + public: + LayerRenderArea(const sp<Layer>& layer, ISurfaceComposer::Rotation rotation) + : RenderArea(layer->getCurrentState().active.h, layer->getCurrentState().active.w, + rotation), + mLayer(layer) {} + 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()); + } + Rect getBounds() const override { + const Layer::State& layerState(mLayer->getDrawingState()); + return Rect(layerState.active.w, layerState.active.h); + } + int getHeight() const override { return mLayer->getDrawingState().active.h; } + int getWidth() const override { return mLayer->getDrawingState().active.w; } + bool isSecure() const override { return false; } + bool needsFiltering() const override { return false; } + + Rect getSourceCrop() const override { return getBounds(); } + + private: + const sp<Layer>& mLayer; + }; + + auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get()); + auto parent = layerHandle->owner.promote(); + + LayerRenderArea renderArea(parent, rotation); + auto traverseLayers = [parent](const LayerVector::Visitor& visitor) { + parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { + if (!layer->isVisible()) { + return; + } + visitor(layer); + }); + }; + return captureScreenCommon(renderArea, traverseLayers, producer, false); +} + +status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + const sp<IGraphicBufferProducer>& producer, + bool useIdentityTransform) { if (CC_UNLIKELY(producer == 0)) return BAD_VALUE; @@ -3784,64 +3854,33 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, // ourselves). bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder(); - // Convert to surfaceflinger's internal rotation type. - Transform::orientation_flags rotationFlags; - switch (rotation) { - case ISurfaceComposer::eRotateNone: - rotationFlags = Transform::ROT_0; - break; - case ISurfaceComposer::eRotate90: - rotationFlags = Transform::ROT_90; - break; - case ISurfaceComposer::eRotate180: - rotationFlags = Transform::ROT_180; - break; - case ISurfaceComposer::eRotate270: - rotationFlags = Transform::ROT_270; - break; - default: - rotationFlags = Transform::ROT_0; - ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation); - break; - } - class MessageCaptureScreen : public MessageBase { SurfaceFlinger* flinger; - sp<IBinder> display; + const RenderArea* renderArea; + TraverseLayersFunction traverseLayers; sp<IGraphicBufferProducer> producer; - Rect sourceCrop; - uint32_t reqWidth, reqHeight; - int32_t minLayerZ,maxLayerZ; bool useIdentityTransform; - Transform::orientation_flags rotation; status_t result; bool isLocalScreenshot; public: - MessageCaptureScreen(SurfaceFlinger* flinger, - const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - Transform::orientation_flags rotation, - bool isLocalScreenshot) - : flinger(flinger), display(display), producer(producer), - sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight), - minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), - useIdentityTransform(useIdentityTransform), - rotation(rotation), result(PERMISSION_DENIED), - isLocalScreenshot(isLocalScreenshot) - { - } + MessageCaptureScreen(SurfaceFlinger* flinger, const RenderArea* renderArea, + TraverseLayersFunction traverseLayers, + const sp<IGraphicBufferProducer>& producer, bool useIdentityTransform, + bool isLocalScreenshot) + : flinger(flinger), + renderArea(renderArea), + traverseLayers(traverseLayers), + producer(producer), + useIdentityTransform(useIdentityTransform), + result(PERMISSION_DENIED), + isLocalScreenshot(isLocalScreenshot) {} status_t getResult() const { return result; } virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); - sp<const DisplayDevice> hw(flinger->getDisplayDeviceLocked(display)); - result = flinger->captureScreenImplLocked(hw, producer, - sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, rotation, isLocalScreenshot); + result = flinger->captureScreenImplLocked(*renderArea, traverseLayers, producer, + useIdentityTransform, isLocalScreenshot); static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result); return true; } @@ -3855,9 +3894,8 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, // the asInterface() call below creates our "fake" BpGraphicBufferProducer // which does the marshaling work forwards to our "fake remote" above. sp<MessageBase> msg = new MessageCaptureScreen(this, - display, IGraphicBufferProducer::asInterface( wrapper ), - sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, rotationFlags, isLocalScreenshot); + &renderArea, traverseLayers, IGraphicBufferProducer::asInterface( wrapper ), + useIdentityTransform, isLocalScreenshot); status_t res = postMessageAsync(msg); if (res == NO_ERROR) { @@ -3866,41 +3904,42 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, return res; } - -void SurfaceFlinger::renderScreenImplLocked( - const sp<const DisplayDevice>& hw, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation) +void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, + bool yswap, bool useIdentityTransform) { ATRACE_CALL(); RenderEngine& engine(getRenderEngine()); // get screen geometry - const int32_t hw_w = hw->getWidth(); - const int32_t hw_h = hw->getHeight(); - const bool filtering = static_cast<int32_t>(reqWidth) != hw_w || - static_cast<int32_t>(reqHeight) != hw_h; + const auto raWidth = renderArea.getWidth(); + const auto raHeight = renderArea.getHeight(); + + const auto reqWidth = renderArea.getReqWidth(); + const auto reqHeight = renderArea.getReqHeight(); + Rect sourceCrop = renderArea.getSourceCrop(); + + const bool filtering = static_cast<int32_t>(reqWidth) != raWidth || + static_cast<int32_t>(reqHeight) != raHeight; // if a default or invalid sourceCrop is passed in, set reasonable values if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) { sourceCrop.setLeftTop(Point(0, 0)); - sourceCrop.setRightBottom(Point(hw_w, hw_h)); + sourceCrop.setRightBottom(Point(raWidth, raHeight)); } // ensure that sourceCrop is inside screen if (sourceCrop.left < 0) { ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left); } - if (sourceCrop.right > hw_w) { - ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w); + if (sourceCrop.right > raWidth) { + ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth); } if (sourceCrop.top < 0) { ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top); } - if (sourceCrop.bottom > hw_h) { - ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h); + if (sourceCrop.bottom > raHeight) { + ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight); } // make sure to clear all GL error flags @@ -3908,77 +3947,35 @@ void SurfaceFlinger::renderScreenImplLocked( // set-up our viewport engine.setViewportAndProjection( - reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation); + reqWidth, reqHeight, sourceCrop, raHeight, yswap, renderArea.getRotationFlags()); engine.disableTexturing(); // redraw the screen entirely... engine.clearWithColor(0, 0, 0, 1); - // We loop through the first level of layers without traversing, - // as we need to interpret min/max layer Z in the top level Z space. - for (const auto& layer : mDrawingState.layersSortedByZ) { - if (layer->getLayerStack() != hw->getLayerStack()) { - continue; - } - const Layer::State& state(layer->getDrawingState()); - if (state.z < minLayerZ || state.z > maxLayerZ) { - continue; - } - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - if (!layer->isVisible()) { - return; - } - if (filtering) layer->setFiltering(true); - layer->draw(hw, useIdentityTransform); - if (filtering) layer->setFiltering(false); - }); - } + traverseLayers([&](Layer* layer) { + if (filtering) layer->setFiltering(true); + layer->draw(renderArea, useIdentityTransform); + if (filtering) layer->setFiltering(false); + }); // compositionComplete is needed for older driver - hw->compositionComplete(); - hw->setViewportAndProjection(); +// hw->compositionComplete(); +// hw->setViewportAndProjection(); } - -status_t SurfaceFlinger::captureScreenImplLocked( - const sp<const DisplayDevice>& hw, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, Transform::orientation_flags rotation, - bool isLocalScreenshot) -{ +status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + const sp<IGraphicBufferProducer>& producer, + bool useIdentityTransform, + bool isLocalScreenshot) { ATRACE_CALL(); - // get screen geometry - uint32_t hw_w = hw->getWidth(); - uint32_t hw_h = hw->getHeight(); - - if (rotation & Transform::ROT_90) { - std::swap(hw_w, hw_h); - } - - if ((reqWidth > hw_w) || (reqHeight > hw_h)) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", - reqWidth, reqHeight, hw_w, hw_h); - return BAD_VALUE; - } - - reqWidth = (!reqWidth) ? hw_w : reqWidth; - reqHeight = (!reqHeight) ? hw_h : reqHeight; - bool secureLayerIsVisible = false; - for (const auto& layer : mDrawingState.layersSortedByZ) { - const Layer::State& state(layer->getDrawingState()); - if ((layer->getLayerStack() != hw->getLayerStack()) || - (state.z < minLayerZ || state.z > maxLayerZ)) { - continue; - } - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) { - secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && - layer->isSecure()); - }); - } + traverseLayers([&](Layer *layer) { + secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && + layer->isSecure()); + }); if (!isLocalScreenshot && secureLayerIsVisible) { ALOGW("FB is protected: PERMISSION_DENIED"); @@ -3996,7 +3993,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; int err = 0; - err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); + err = native_window_set_buffers_dimensions(window, renderArea.getReqWidth(), + renderArea.getReqHeight()); err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); err |= native_window_set_usage(window, usage); @@ -4022,9 +4020,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( // via an FBO, which means we didn't have to create // an EGLSurface and therefore we're not // dependent on the context's EGLConfig. - renderScreenImplLocked( - hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true, - useIdentityTransform, rotation); + renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform); // Attempt to create a sync khr object that can produce a sync point. If that // isn't available, create a non-dupable sync object in the fallback path and @@ -4064,10 +4060,12 @@ status_t SurfaceFlinger::captureScreenImplLocked( } } if (DEBUG_SCREENSHOTS) { - uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; - getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); - checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, - hw, minLayerZ, maxLayerZ); + uint32_t* pixels = new uint32_t[renderArea.getReqWidth() * + renderArea.getReqHeight()]; + getRenderEngine().readPixels(0, 0, renderArea.getReqWidth(), + renderArea.getReqHeight(), pixels); + checkScreenshot(renderArea.getReqWidth(), renderArea.getReqHeight(), + renderArea.getReqWidth(), pixels, traverseLayers); delete [] pixels; } @@ -4097,7 +4095,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( } void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, - const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) { + TraverseLayersFunction traverseLayers) { if (DEBUG_SCREENSHOTS) { for (size_t y=0 ; y<h ; y++) { uint32_t const * p = (uint32_t const *)vaddr + y*s; @@ -4105,23 +4103,17 @@ void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* v if (p[x] != 0xFF000000) return; } } - ALOGE("*** we just took a black screenshot ***\n" - "requested minz=%d, maxz=%d, layerStack=%d", - minLayerZ, maxLayerZ, hw->getLayerStack()); + ALOGE("*** we just took a black screenshot ***"); + size_t i = 0; - for (const auto& layer : mDrawingState.layersSortedByZ) { + traverseLayers([&](Layer* layer) { const Layer::State& state(layer->getDrawingState()); - if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ && - state.z <= maxLayerZ) { - layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f", - layer->isVisible() ? '+' : '-', - i, layer->getName().string(), layer->getLayerStack(), state.z, - layer->isVisible(), state.flags, static_cast<float>(state.color.a)); - i++; - }); - } - } + ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f", + layer->isVisible() ? '+' : '-', + i, layer->getName().string(), layer->getLayerStack(), state.z, + layer->isVisible(), state.flags, static_cast<float>(state.color.a)); + i++; + }); } } @@ -4135,6 +4127,28 @@ void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& layersSortedByZ.traverseInReverseZOrder(stateSet, visitor); } +void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw, + int32_t minLayerZ, int32_t maxLayerZ, const LayerVector::Visitor& visitor) { + + // We loop through the first level of layers without traversing, + // as we need to interpret min/max layer Z in the top level Z space. + for (const auto& layer : mDrawingState.layersSortedByZ) { + if (!layer->belongsToDisplay(hw->getLayerStack(), false)) { + continue; + } + const Layer::State& state(layer->getDrawingState()); + if (state.z < minLayerZ || state.z > maxLayerZ) { + continue; + } + layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { + if (!layer->isVisible()) { + return; + } + visitor(layer); + }); + } +} + }; // namespace android diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp index 6be9ae2c5f..37925a1641 100644 --- a/services/surfaceflinger/Transform.cpp +++ b/services/surfaceflinger/Transform.cpp @@ -20,8 +20,8 @@ #include <utils/String8.h> #include <ui/Region.h> -#include "clz.h" #include "Transform.h" +#include "clz.h" // --------------------------------------------------------------------------- @@ -388,6 +388,23 @@ void Transform::dump(const char* name) const ALOGD("%.4f %.4f %.4f", m[0][2], m[1][2], m[2][2]); } +Transform::orientation_flags Transform::fromRotation(ISurfaceComposer::Rotation rotation) { + // Convert to surfaceflinger's internal rotation type. + switch (rotation) { + case ISurfaceComposer::eRotateNone: + return Transform::ROT_0; + case ISurfaceComposer::eRotate90: + return Transform::ROT_90; + case ISurfaceComposer::eRotate180: + return Transform::ROT_180; + case ISurfaceComposer::eRotate270: + return Transform::ROT_270; + default: + ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation); + return Transform::ROT_0; + } +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h index 6640a13839..bfc66eccb9 100644 --- a/services/surfaceflinger/Transform.h +++ b/services/surfaceflinger/Transform.h @@ -25,6 +25,8 @@ #include <math/vec2.h> #include <math/vec3.h> +#include <gui/ISurfaceComposer.h> + #include <hardware/hardware.h> namespace android { @@ -51,6 +53,8 @@ public: ROT_INVALID = 0x80 }; + static orientation_flags fromRotation(ISurfaceComposer::Rotation rotation); + enum type_mask { IDENTITY = 0, TRANSLATE = 0x1, diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index f61a978487..ec87eeec77 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -116,6 +116,60 @@ private: CpuConsumer::LockedBuffer mBuf; }; +class CaptureLayer { +public: + static void captureScreen(std::unique_ptr<CaptureLayer>* sc, sp<IBinder>& parentHandle) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + sp<IBinder> display(sf->getBuiltInDisplay( + ISurfaceComposer::eDisplayIdMain)); + SurfaceComposerClient::Transaction().apply(true); + ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, producer)); + *sc = std::make_unique<CaptureLayer>(cpuConsumer); + } + + void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { + ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuffer.format); + const uint8_t* img = static_cast<const uint8_t*>(mBuffer.data); + const uint8_t* pixel = img + (4 * (y * mBuffer.stride + x)); + if (r != pixel[0] || g != pixel[1] || b != pixel[2]) { + String8 err(String8::format("pixel @ (%3d, %3d): " + "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", + x, y, r, g, b, pixel[0], pixel[1], pixel[2])); + EXPECT_EQ(String8(), err) << err.string(); + } + } + + void expectFGColor(uint32_t x, uint32_t y) { + checkPixel(x, y, 195, 63, 63); + } + + void expectBGColor(uint32_t x, uint32_t y) { + checkPixel(x, y, 63, 63, 195); + } + + void expectChildColor(uint32_t x, uint32_t y) { + checkPixel(x, y, 200, 200, 200); + } + + CaptureLayer(const sp<CpuConsumer>& cc) : + mCC(cc) { + EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuffer)); + } + + ~CaptureLayer() { + mCC->unlockBuffer(mBuffer); + } + +private: + sp<CpuConsumer> mCC; + CpuConsumer::LockedBuffer mBuffer; +}; + + class LayerUpdateTest : public ::testing::Test { protected: virtual void SetUp() { @@ -1431,4 +1485,109 @@ TEST_F(LayerColorTest, ColorLayerWithNoColor) { } } +class ScreenCaptureTest : public LayerUpdateTest { +protected: + std::unique_ptr<CaptureLayer> mCapture; +}; + +TEST_F(ScreenCaptureTest, CaptureSingleLayer) { + auto bgHandle = mBGSurfaceControl->getHandle(); + CaptureLayer::captureScreen(&mCapture, bgHandle); + mCapture->expectBGColor(0, 0); + // Doesn't capture FG layer which is at 64, 64 + mCapture->expectBGColor(64, 64); +} + +TEST_F(ScreenCaptureTest, CaptureLayerWithChild) { + 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 layer and its child. + CaptureLayer::captureScreen(&mCapture, fgHandle); + mCapture->expectFGColor(10, 10); + mCapture->expectChildColor(0, 0); +} + +TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) { + 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); + + sp<SurfaceControl> grandchild = mComposerClient->createSurface( + String8("Grandchild surface"), 5, 5, + PIXEL_FORMAT_RGBA_8888, 0, child.get()); + + fillSurfaceRGBA8(grandchild, 50, 50, 50); + SurfaceComposerClient::Transaction() + .show(child) + .setPosition(grandchild, 5, 5) + .show(grandchild) + .apply(true); + + // Captures mFGSurfaceControl, its child, and the grandchild. + CaptureLayer::captureScreen(&mCapture, fgHandle); + mCapture->expectFGColor(10, 10); + mCapture->expectChildColor(0, 0); + mCapture->checkPixel(5, 5, 50, 50, 50); +} + +TEST_F(ScreenCaptureTest, CaptureChildOnly) { + sp<SurfaceControl> child = mComposerClient->createSurface( + String8("Child surface"), + 10, 10, PIXEL_FORMAT_RGBA_8888, + 0, mFGSurfaceControl.get()); + fillSurfaceRGBA8(child, 200, 200, 200); + auto childHandle = child->getHandle(); + + SurfaceComposerClient::Transaction() + .setPosition(child, 5, 5) + .show(child) + .apply(true); + + // Captures only the child layer, and not the parent. + CaptureLayer::captureScreen(&mCapture, childHandle); + mCapture->expectChildColor(0, 0); + mCapture->expectChildColor(9, 9); +} + +TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) { + sp<SurfaceControl> child = mComposerClient->createSurface( + String8("Child surface"), + 10, 10, PIXEL_FORMAT_RGBA_8888, + 0, mFGSurfaceControl.get()); + fillSurfaceRGBA8(child, 200, 200, 200); + auto childHandle = child->getHandle(); + + sp<SurfaceControl> grandchild = mComposerClient->createSurface( + String8("Grandchild surface"), 5, 5, + PIXEL_FORMAT_RGBA_8888, 0, child.get()); + fillSurfaceRGBA8(grandchild, 50, 50, 50); + + SurfaceComposerClient::Transaction() + .show(child) + .setPosition(grandchild, 5, 5) + .show(grandchild) + .apply(true); + + auto grandchildHandle = grandchild->getHandle(); + + // Captures only the grandchild. + CaptureLayer::captureScreen(&mCapture, grandchildHandle); + mCapture->checkPixel(0, 0, 50, 50, 50); + mCapture->checkPixel(4, 4, 50, 50, 50); +} + } |