Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a4d0dfd authored by Jamie Gennis's avatar Jamie Gennis
Browse files

SurfaceFlinger: Respect the PROTECTED gralloc bit.

This change makes SurfaceFlinger treat layers for which the active
buffer has the GRALLOC_USAGE_PROTECTED bit set as if they have the
'secure' flag set.

Change-Id: Ic60b6513a63e4bb92ec6ce9fd12fd39b4ba5f674
Bug: 4081304
parent 87c3bfac
Loading
Loading
Loading
Loading
+59 −6
Original line number Diff line number Diff line
@@ -15,22 +15,19 @@
 */

#include <gtest/gtest.h>

#include <binder/IMemory.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/Surface.h>
#include <surfaceflinger/SurfaceComposerClient.h>

#include <utils/String8.h>

namespace android {

class SurfaceTest : public ::testing::Test {
protected:
    virtual sp<SurfaceComposerClient> getSurfaceComposerClient() {
        return sp<SurfaceComposerClient>(new SurfaceComposerClient);
    }

    virtual void SetUp() {
        mComposerClient = getSurfaceComposerClient();
        mComposerClient = new SurfaceComposerClient;
        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());

        mSurfaceControl = mComposerClient->createSurface(getpid(),
@@ -77,4 +74,60 @@ TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) {
    EXPECT_EQ(1, result);
}

// This test probably doesn't belong here.
TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) {
    sp<ANativeWindow> anw(mSurface);

    // Verify the screenshot works with no protected buffers.
    sp<IMemoryHeap> heap;
    uint32_t w=0, h=0;
    PixelFormat fmt=0;
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
            40000));
    ASSERT_TRUE(heap != NULL);

    // Set the PROTECTED usage bit and verify that the screenshot fails.  Note
    // that we need to dequeue a buffer in order for it to actually get
    // allocated in SurfaceFlinger.
    ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
            GRALLOC_USAGE_PROTECTED));
    ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
    android_native_buffer_t* buf = 0;
    for (int i = 0; i < 4; i++) {
        // Loop to make sure SurfaceFlinger has retired a protected buffer.
        ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
        ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
        ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
    }
    heap = 0;
    w = h = fmt = 0;
    ASSERT_EQ(INVALID_OPERATION, sf->captureScreen(0, &heap, &w, &h, &fmt,
            64, 64, 0, 40000));
    ASSERT_TRUE(heap == NULL);

    // XXX: This should not be needed, but it seems that the new buffers don't
    // correctly show up after the upcoming dequeue/lock/queue loop without it.
    // We should look into this at some point.
    ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));

    // Un-set the PROTECTED usage bit and verify that the screenshot works
    // again.  Note that we have to change the buffers geometry to ensure that
    // the buffers get reallocated, as the new usage bits are a subset of the
    // old.
    ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0));
    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(anw.get(), 32, 32, 0));
    for (int i = 0; i < 4; i++) {
        // Loop to make sure SurfaceFlinger has retired a protected buffer.
        ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
        ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
        ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
    }
    heap = 0;
    w = h = fmt = 0;
    ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
            40000));
    ASSERT_TRUE(heap != NULL);
}

}
+7 −3
Original line number Diff line number Diff line
@@ -57,7 +57,6 @@ Layer::Layer(SurfaceFlinger* flinger,
        mNeedsDithering(false),
        mSecure(false),
        mProtectedByApp(false),
        mProtectedByDRM(false),
        mTextureManager(),
        mBufferManager(mTextureManager),
        mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false)
@@ -191,7 +190,6 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,

    mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
    mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
    mProtectedByDRM = (flags & ISurfaceComposer::eProtectedByDRM) ? true : false;
    mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
            (flags & ISurfaceComposer::eOpaque) == 0;

@@ -392,6 +390,12 @@ bool Layer::needsFiltering() const
    return LayerBase::needsFiltering();
}

bool Layer::isProtected() const
{
    sp<GraphicBuffer> activeBuffer(mBufferManager.getActiveBuffer());
    return (activeBuffer != 0) &&
            (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}

status_t Layer::setBufferCount(int bufferCount)
{
@@ -515,7 +519,7 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const
        // request EGLImage for all buffers
        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
    }
    if (mProtectedByApp || mProtectedByDRM) {
    if (mProtectedByApp) {
        // need a hardware-protected path to external video sink
        usage |= GraphicBuffer::USAGE_PROTECTED;
    }
+1 −3
Original line number Diff line number Diff line
@@ -80,8 +80,7 @@ public:
    virtual bool needsDithering() const     { return mNeedsDithering; }
    virtual bool needsFiltering() const;
    virtual bool isSecure() const           { return mSecure; }
    virtual bool isProtectedByApp() const   { return mProtectedByApp; }
    virtual bool isProtectedByDRM() const   { return mProtectedByDRM; }
    virtual bool isProtected() const;
    virtual sp<Surface> createSurface() const;
    virtual status_t ditch();
    virtual void onRemoved();
@@ -222,7 +221,6 @@ private:
    // page-flip thread (currently main thread)
    bool mSecure;         // no screenshots
    bool mProtectedByApp; // application requires protected path to external sink
    bool mProtectedByDRM; // DRM agent requires protected path to external sink
    Region mPostedDirtyRegion;

    // page-flip thread and transaction thread (currently main thread)
+3 −9
Original line number Diff line number Diff line
@@ -197,16 +197,10 @@ public:
    virtual bool isSecure() const       { return false; }

    /**
     * isProtectedByApp - true if application says this surface is protected, that
     * is if it requires a hardware-protected data path to an external sink.
     * isProtected - true if the layer may contain protected content in the
     * GRALLOC_USAGE_PROTECTED sense.
     */
    virtual bool isProtectedByApp() const   { return false; }

    /**
     * isProtectedByDRM - true if DRM agent says this surface is protected, that
     * is if it requires a hardware-protected data path to an external sink.
     */
    virtual bool isProtectedByDRM() const   { return false; }
    virtual bool isProtected() const   { return false; }

    /** Called from the main thread, when the surface is removed from the
     * draw list */
+13 −2
Original line number Diff line number Diff line
@@ -2169,6 +2169,19 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
    if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
        return BAD_VALUE;

    // make sure none of the layers are protected
    const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
    const size_t count = layers.size();
    for (size_t i=0 ; i<count ; ++i) {
        const sp<LayerBase>& layer(layers[i]);
        const uint32_t z = layer->drawingState().z;
        if (z >= minLayerZ && z <= maxLayerZ) {
            if (layer->isProtected()) {
                return INVALID_OPERATION;
            }
        }
    }

    if (!GLExtensions::getInstance().haveFramebufferObject())
        return INVALID_OPERATION;

@@ -2217,8 +2230,6 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
        glClearColor(0,0,0,1);
        glClear(GL_COLOR_BUFFER_BIT);

        const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
        const size_t count = layers.size();
        for (size_t i=0 ; i<count ; ++i) {
            const sp<LayerBase>& layer(layers[i]);
            const uint32_t z = layer->drawingState().z;