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
This commit is contained in:
parent
87c3bfac18
commit
7a4d0dfd43
|
@ -15,22 +15,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <binder/IMemory.h>
|
||||||
#include <surfaceflinger/ISurfaceComposer.h>
|
#include <surfaceflinger/ISurfaceComposer.h>
|
||||||
#include <surfaceflinger/Surface.h>
|
#include <surfaceflinger/Surface.h>
|
||||||
#include <surfaceflinger/SurfaceComposerClient.h>
|
#include <surfaceflinger/SurfaceComposerClient.h>
|
||||||
|
|
||||||
#include <utils/String8.h>
|
#include <utils/String8.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
class SurfaceTest : public ::testing::Test {
|
class SurfaceTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
virtual sp<SurfaceComposerClient> getSurfaceComposerClient() {
|
|
||||||
return sp<SurfaceComposerClient>(new SurfaceComposerClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
mComposerClient = getSurfaceComposerClient();
|
mComposerClient = new SurfaceComposerClient;
|
||||||
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
|
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
|
||||||
|
|
||||||
mSurfaceControl = mComposerClient->createSurface(getpid(),
|
mSurfaceControl = mComposerClient->createSurface(getpid(),
|
||||||
|
@ -77,4 +74,60 @@ TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) {
|
||||||
EXPECT_EQ(1, result);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,6 @@ Layer::Layer(SurfaceFlinger* flinger,
|
||||||
mNeedsDithering(false),
|
mNeedsDithering(false),
|
||||||
mSecure(false),
|
mSecure(false),
|
||||||
mProtectedByApp(false),
|
mProtectedByApp(false),
|
||||||
mProtectedByDRM(false),
|
|
||||||
mTextureManager(),
|
mTextureManager(),
|
||||||
mBufferManager(mTextureManager),
|
mBufferManager(mTextureManager),
|
||||||
mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false)
|
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;
|
mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
|
||||||
mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
|
mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
|
||||||
mProtectedByDRM = (flags & ISurfaceComposer::eProtectedByDRM) ? true : false;
|
|
||||||
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
|
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
|
||||||
(flags & ISurfaceComposer::eOpaque) == 0;
|
(flags & ISurfaceComposer::eOpaque) == 0;
|
||||||
|
|
||||||
|
@ -392,6 +390,12 @@ bool Layer::needsFiltering() const
|
||||||
return LayerBase::needsFiltering();
|
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)
|
status_t Layer::setBufferCount(int bufferCount)
|
||||||
{
|
{
|
||||||
|
@ -515,7 +519,7 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const
|
||||||
// request EGLImage for all buffers
|
// request EGLImage for all buffers
|
||||||
usage |= GraphicBuffer::USAGE_HW_TEXTURE;
|
usage |= GraphicBuffer::USAGE_HW_TEXTURE;
|
||||||
}
|
}
|
||||||
if (mProtectedByApp || mProtectedByDRM) {
|
if (mProtectedByApp) {
|
||||||
// need a hardware-protected path to external video sink
|
// need a hardware-protected path to external video sink
|
||||||
usage |= GraphicBuffer::USAGE_PROTECTED;
|
usage |= GraphicBuffer::USAGE_PROTECTED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,7 @@ public:
|
||||||
virtual bool needsDithering() const { return mNeedsDithering; }
|
virtual bool needsDithering() const { return mNeedsDithering; }
|
||||||
virtual bool needsFiltering() const;
|
virtual bool needsFiltering() const;
|
||||||
virtual bool isSecure() const { return mSecure; }
|
virtual bool isSecure() const { return mSecure; }
|
||||||
virtual bool isProtectedByApp() const { return mProtectedByApp; }
|
virtual bool isProtected() const;
|
||||||
virtual bool isProtectedByDRM() const { return mProtectedByDRM; }
|
|
||||||
virtual sp<Surface> createSurface() const;
|
virtual sp<Surface> createSurface() const;
|
||||||
virtual status_t ditch();
|
virtual status_t ditch();
|
||||||
virtual void onRemoved();
|
virtual void onRemoved();
|
||||||
|
@ -222,7 +221,6 @@ private:
|
||||||
// page-flip thread (currently main thread)
|
// page-flip thread (currently main thread)
|
||||||
bool mSecure; // no screenshots
|
bool mSecure; // no screenshots
|
||||||
bool mProtectedByApp; // application requires protected path to external sink
|
bool mProtectedByApp; // application requires protected path to external sink
|
||||||
bool mProtectedByDRM; // DRM agent requires protected path to external sink
|
|
||||||
Region mPostedDirtyRegion;
|
Region mPostedDirtyRegion;
|
||||||
|
|
||||||
// page-flip thread and transaction thread (currently main thread)
|
// page-flip thread and transaction thread (currently main thread)
|
||||||
|
|
|
@ -197,16 +197,10 @@ public:
|
||||||
virtual bool isSecure() const { return false; }
|
virtual bool isSecure() const { return false; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* isProtectedByApp - true if application says this surface is protected, that
|
* isProtected - true if the layer may contain protected content in the
|
||||||
* is if it requires a hardware-protected data path to an external sink.
|
* GRALLOC_USAGE_PROTECTED sense.
|
||||||
*/
|
*/
|
||||||
virtual bool isProtectedByApp() const { return false; }
|
virtual bool isProtected() 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; }
|
|
||||||
|
|
||||||
/** Called from the main thread, when the surface is removed from the
|
/** Called from the main thread, when the surface is removed from the
|
||||||
* draw list */
|
* draw list */
|
||||||
|
|
|
@ -2169,6 +2169,19 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
|
||||||
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
||||||
return BAD_VALUE;
|
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())
|
if (!GLExtensions::getInstance().haveFramebufferObject())
|
||||||
return INVALID_OPERATION;
|
return INVALID_OPERATION;
|
||||||
|
|
||||||
|
@ -2217,8 +2230,6 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
|
||||||
glClearColor(0,0,0,1);
|
glClearColor(0,0,0,1);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
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) {
|
for (size_t i=0 ; i<count ; ++i) {
|
||||||
const sp<LayerBase>& layer(layers[i]);
|
const sp<LayerBase>& layer(layers[i]);
|
||||||
const uint32_t z = layer->drawingState().z;
|
const uint32_t z = layer->drawingState().z;
|
||||||
|
|
Loading…
Reference in New Issue