rework how we take screenshots for a CPU consumer
We're not using IMemoryHeap as a transport anymore, instead we're providing a CpuConsumer and use the IGraphicBufferProducer version of the screenshot API. However, some GPU drivers don't support properly a GPU to CPU path, to work around this, we use a temporary BufferQueue on the server side for the GL rendering, and we use glReadPixels into the CpuConsumer (we're now using a CPU to CPU path which is always supported). Currently this "wrapping" is always performed, but it can be bypassed on devices that support the GPU to CPU path. This also addresses a DoS attack vector on SurfaceFlinger, where an application could consume all of SF's filedescriptors by creating a lot of screenshots in a row. Bug: 8390553 Change-Id: I9e81514c2a7711b9bb393f74305be7d2abe08f1c
This commit is contained in:
parent
9cd766a517
commit
abe815dd69
|
@ -95,14 +95,6 @@ public:
|
|||
virtual bool authenticateSurfaceTexture(
|
||||
const sp<IGraphicBufferProducer>& surface) const = 0;
|
||||
|
||||
/* Capture the specified screen. requires READ_FRAME_BUFFER permission
|
||||
* This function will fail if there is a secure window on screen.
|
||||
*/
|
||||
virtual status_t captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* heap,
|
||||
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
|
||||
|
||||
/* triggers screen off and waits for it to complete
|
||||
* requires ACCESS_SURFACE_FLINGER permission.
|
||||
*/
|
||||
|
@ -123,7 +115,8 @@ public:
|
|||
virtual status_t captureScreen(const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ,
|
||||
bool isCpuConsumer) = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -141,7 +134,6 @@ public:
|
|||
GET_BUILT_IN_DISPLAY,
|
||||
SET_TRANSACTION_STATE,
|
||||
AUTHENTICATE_SURFACE,
|
||||
CAPTURE_SCREEN_DEPRECATED,
|
||||
BLANK,
|
||||
UNBLANK,
|
||||
GET_DISPLAY_INFO,
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <ui/PixelFormat.h>
|
||||
|
||||
#include <gui/CpuConsumer.h>
|
||||
#include <gui/SurfaceControl.h>
|
||||
|
||||
namespace android {
|
||||
|
@ -38,7 +39,6 @@ namespace android {
|
|||
|
||||
class DisplayInfo;
|
||||
class Composer;
|
||||
class IMemoryHeap;
|
||||
class ISurfaceComposerClient;
|
||||
class IGraphicBufferProducer;
|
||||
class Region;
|
||||
|
@ -164,10 +164,9 @@ public:
|
|||
uint32_t minLayerZ, uint32_t maxLayerZ);
|
||||
|
||||
private:
|
||||
sp<IMemoryHeap> mHeap;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
PixelFormat mFormat;
|
||||
mutable sp<CpuConsumer> mCpuConsumer;
|
||||
CpuConsumer::LockedBuffer mBuffer;
|
||||
bool mHaveBuffer;
|
||||
|
||||
public:
|
||||
ScreenshotClient();
|
||||
|
@ -180,6 +179,8 @@ public:
|
|||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ);
|
||||
|
||||
sp<CpuConsumer> getCpuConsumer() const;
|
||||
|
||||
// release memory occupied by the screenshot
|
||||
void release();
|
||||
|
||||
|
|
|
@ -102,31 +102,11 @@ public:
|
|||
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
|
||||
}
|
||||
|
||||
virtual status_t captureScreen(
|
||||
const sp<IBinder>& display, sp<IMemoryHeap>* heap,
|
||||
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
|
||||
data.writeStrongBinder(display);
|
||||
data.writeInt32(reqWidth);
|
||||
data.writeInt32(reqHeight);
|
||||
data.writeInt32(minLayerZ);
|
||||
data.writeInt32(maxLayerZ);
|
||||
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN_DEPRECATED, data, &reply);
|
||||
*heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
|
||||
*width = reply.readInt32();
|
||||
*height = reply.readInt32();
|
||||
*format = reply.readInt32();
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
||||
virtual status_t captureScreen(const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ,
|
||||
bool isCpuConsumer)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
|
||||
|
@ -136,6 +116,7 @@ public:
|
|||
data.writeInt32(reqHeight);
|
||||
data.writeInt32(minLayerZ);
|
||||
data.writeInt32(maxLayerZ);
|
||||
data.writeInt32(isCpuConsumer);
|
||||
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
@ -285,24 +266,6 @@ status_t BnSurfaceComposer::onTransact(
|
|||
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
||||
bootFinished();
|
||||
} break;
|
||||
case CAPTURE_SCREEN_DEPRECATED: {
|
||||
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
||||
sp<IBinder> display = data.readStrongBinder();
|
||||
uint32_t reqWidth = data.readInt32();
|
||||
uint32_t reqHeight = data.readInt32();
|
||||
uint32_t minLayerZ = data.readInt32();
|
||||
uint32_t maxLayerZ = data.readInt32();
|
||||
sp<IMemoryHeap> heap;
|
||||
uint32_t w, h;
|
||||
PixelFormat f;
|
||||
status_t res = captureScreen(display, &heap, &w, &h, &f,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
reply->writeStrongBinder(heap->asBinder());
|
||||
reply->writeInt32(w);
|
||||
reply->writeInt32(h);
|
||||
reply->writeInt32(f);
|
||||
reply->writeInt32(res);
|
||||
} break;
|
||||
case CAPTURE_SCREEN: {
|
||||
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
||||
sp<IBinder> display = data.readStrongBinder();
|
||||
|
@ -312,8 +275,10 @@ status_t BnSurfaceComposer::onTransact(
|
|||
uint32_t reqHeight = data.readInt32();
|
||||
uint32_t minLayerZ = data.readInt32();
|
||||
uint32_t maxLayerZ = data.readInt32();
|
||||
bool isCpuConsumer = data.readInt32();
|
||||
status_t res = captureScreen(display, producer,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ,
|
||||
isCpuConsumer);
|
||||
reply->writeInt32(res);
|
||||
} break;
|
||||
case AUTHENTICATE_SURFACE: {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include <ui/DisplayInfo.h>
|
||||
|
||||
#include <gui/CpuConsumer.h>
|
||||
#include <gui/IGraphicBufferProducer.h>
|
||||
#include <gui/ISurfaceComposer.h>
|
||||
#include <gui/ISurfaceComposerClient.h>
|
||||
|
@ -617,30 +618,21 @@ status_t ScreenshotClient::capture(
|
|||
sp<ISurfaceComposer> s(ComposerService::getComposerService());
|
||||
if (s == NULL) return NO_INIT;
|
||||
return s->captureScreen(display, producer,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ,
|
||||
false);
|
||||
}
|
||||
|
||||
ScreenshotClient::ScreenshotClient()
|
||||
: mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
|
||||
: mHaveBuffer(false) {
|
||||
memset(&mBuffer, 0, sizeof(mBuffer));
|
||||
}
|
||||
|
||||
status_t ScreenshotClient::update(const sp<IBinder>& display) {
|
||||
sp<ISurfaceComposer> s(ComposerService::getComposerService());
|
||||
if (s == NULL) return NO_INIT;
|
||||
mHeap = 0;
|
||||
return s->captureScreen(display, &mHeap,
|
||||
&mWidth, &mHeight, &mFormat, 0, 0,
|
||||
0, -1UL);
|
||||
}
|
||||
|
||||
status_t ScreenshotClient::update(const sp<IBinder>& display,
|
||||
uint32_t reqWidth, uint32_t reqHeight) {
|
||||
sp<ISurfaceComposer> s(ComposerService::getComposerService());
|
||||
if (s == NULL) return NO_INIT;
|
||||
mHeap = 0;
|
||||
return s->captureScreen(display, &mHeap,
|
||||
&mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
|
||||
0, -1UL);
|
||||
sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
|
||||
if (mCpuConsumer == NULL) {
|
||||
mCpuConsumer = new CpuConsumer(1);
|
||||
mCpuConsumer->setName(String8("ScreenshotClient"));
|
||||
}
|
||||
return mCpuConsumer;
|
||||
}
|
||||
|
||||
status_t ScreenshotClient::update(const sp<IBinder>& display,
|
||||
|
@ -648,38 +640,66 @@ status_t ScreenshotClient::update(const sp<IBinder>& display,
|
|||
uint32_t minLayerZ, uint32_t maxLayerZ) {
|
||||
sp<ISurfaceComposer> s(ComposerService::getComposerService());
|
||||
if (s == NULL) return NO_INIT;
|
||||
mHeap = 0;
|
||||
return s->captureScreen(display, &mHeap,
|
||||
&mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
|
||||
minLayerZ, maxLayerZ);
|
||||
sp<CpuConsumer> cpuConsumer = getCpuConsumer();
|
||||
|
||||
if (mHaveBuffer) {
|
||||
mCpuConsumer->unlockBuffer(mBuffer);
|
||||
memset(&mBuffer, 0, sizeof(mBuffer));
|
||||
mHaveBuffer = false;
|
||||
}
|
||||
|
||||
status_t err = s->captureScreen(display,cpuConsumer->getBufferQueue(),
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ, true);
|
||||
|
||||
if (err == NO_ERROR) {
|
||||
err = mCpuConsumer->lockNextBuffer(&mBuffer);
|
||||
if (err == NO_ERROR) {
|
||||
mHaveBuffer = true;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t ScreenshotClient::update(const sp<IBinder>& display) {
|
||||
return ScreenshotClient::update(display, 0, 0, 0, -1UL);
|
||||
}
|
||||
|
||||
status_t ScreenshotClient::update(const sp<IBinder>& display,
|
||||
uint32_t reqWidth, uint32_t reqHeight) {
|
||||
return ScreenshotClient::update(display, reqWidth, reqHeight, 0, -1UL);
|
||||
}
|
||||
|
||||
void ScreenshotClient::release() {
|
||||
mHeap = 0;
|
||||
if (mHaveBuffer) {
|
||||
mCpuConsumer->unlockBuffer(mBuffer);
|
||||
memset(&mBuffer, 0, sizeof(mBuffer));
|
||||
mHaveBuffer = false;
|
||||
}
|
||||
mCpuConsumer.clear();
|
||||
}
|
||||
|
||||
void const* ScreenshotClient::getPixels() const {
|
||||
return mHeap->getBase();
|
||||
return mBuffer.data;
|
||||
}
|
||||
|
||||
uint32_t ScreenshotClient::getWidth() const {
|
||||
return mWidth;
|
||||
return mBuffer.width;
|
||||
}
|
||||
|
||||
uint32_t ScreenshotClient::getHeight() const {
|
||||
return mHeight;
|
||||
return mBuffer.height;
|
||||
}
|
||||
|
||||
PixelFormat ScreenshotClient::getFormat() const {
|
||||
return mFormat;
|
||||
return mBuffer.format;
|
||||
}
|
||||
|
||||
uint32_t ScreenshotClient::getStride() const {
|
||||
return mWidth;
|
||||
return mBuffer.stride;
|
||||
}
|
||||
|
||||
size_t ScreenshotClient::getSize() const {
|
||||
return mHeap->getSize();
|
||||
return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -2416,7 +2416,6 @@ status_t SurfaceFlinger::onTransact(
|
|||
break;
|
||||
}
|
||||
case CAPTURE_SCREEN:
|
||||
case CAPTURE_SCREEN_DEPRECATED:
|
||||
{
|
||||
// codes that require permission check
|
||||
IPCThreadState* ipc = IPCThreadState::self();
|
||||
|
@ -2511,7 +2510,8 @@ void SurfaceFlinger::repaintEverything() {
|
|||
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ) {
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ,
|
||||
bool isCpuConsumer) {
|
||||
|
||||
if (CC_UNLIKELY(display == 0))
|
||||
return BAD_VALUE;
|
||||
|
@ -2525,16 +2525,18 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
|
|||
sp<IGraphicBufferProducer> producer;
|
||||
uint32_t reqWidth, reqHeight;
|
||||
uint32_t minLayerZ,maxLayerZ;
|
||||
bool isCpuConsumer;
|
||||
status_t result;
|
||||
public:
|
||||
MessageCaptureScreen(SurfaceFlinger* flinger,
|
||||
const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer)
|
||||
: flinger(flinger), display(display), producer(producer),
|
||||
reqWidth(reqWidth), reqHeight(reqHeight),
|
||||
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
|
||||
isCpuConsumer(isCpuConsumer),
|
||||
result(PERMISSION_DENIED)
|
||||
{
|
||||
}
|
||||
|
@ -2544,14 +2546,24 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
|
|||
virtual bool handler() {
|
||||
Mutex::Autolock _l(flinger->mStateLock);
|
||||
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
|
||||
result = flinger->captureScreenImplLocked(hw, producer,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
// TODO: if we know the GL->CPU path works, we can call
|
||||
// captureScreenImplLocked() directly, instead of using the
|
||||
// "CpuConsumer" version, which is much less efficient -- it is
|
||||
// however needed by some older drivers.
|
||||
if (isCpuConsumer) {
|
||||
result = flinger->captureScreenImplCpuConsumerLocked(hw,
|
||||
producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
} else {
|
||||
result = flinger->captureScreenImplLocked(hw,
|
||||
producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
sp<MessageBase> msg = new MessageCaptureScreen(this,
|
||||
display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ,
|
||||
isCpuConsumer);
|
||||
status_t res = postMessageSync(msg);
|
||||
if (res == NO_ERROR) {
|
||||
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
|
||||
|
@ -2655,18 +2667,15 @@ status_t SurfaceFlinger::captureScreenImplLocked(
|
|||
}
|
||||
|
||||
eglDestroySurface(mEGLDisplay, eglSurface);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Capture screen into an IMemoryHeap (legacy)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
status_t SurfaceFlinger::captureScreenImplLocked(
|
||||
status_t SurfaceFlinger::captureScreenImplCpuConsumerLocked(
|
||||
const sp<const DisplayDevice>& hw,
|
||||
sp<IMemoryHeap>* heap,
|
||||
uint32_t* w, uint32_t* h, PixelFormat* f,
|
||||
uint32_t sw, uint32_t sh,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
{
|
||||
ATRACE_CALL();
|
||||
|
@ -2689,7 +2698,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
|
|||
|
||||
// call the new screenshot taking code, passing a BufferQueue to it
|
||||
status_t result = captureScreenImplLocked(hw,
|
||||
consumer->getBufferQueue(), sw, sh, minLayerZ, maxLayerZ);
|
||||
consumer->getBufferQueue(), reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
|
||||
if (result == NO_ERROR) {
|
||||
result = consumer->updateTexImage();
|
||||
|
@ -2701,31 +2710,64 @@ status_t SurfaceFlinger::captureScreenImplLocked(
|
|||
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
|
||||
GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
|
||||
|
||||
sp<GraphicBuffer> buf(consumer->getCurrentBuffer());
|
||||
sw = buf->getWidth();
|
||||
sh = buf->getHeight();
|
||||
size_t size = sw * sh * 4;
|
||||
reqWidth = consumer->getCurrentBuffer()->getWidth();
|
||||
reqHeight = consumer->getCurrentBuffer()->getHeight();
|
||||
|
||||
// allocate shared memory large enough to hold the
|
||||
// screen capture
|
||||
sp<MemoryHeapBase> base(
|
||||
new MemoryHeapBase(size, 0, "screen-capture") );
|
||||
void* const ptr = base->getBase();
|
||||
if (ptr != MAP_FAILED) {
|
||||
// capture the screen with glReadPixels()
|
||||
ScopedTrace _t(ATRACE_TAG, "glReadPixels");
|
||||
glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
|
||||
if (glGetError() == GL_NO_ERROR) {
|
||||
*heap = base;
|
||||
*w = sw;
|
||||
*h = sh;
|
||||
*f = PIXEL_FORMAT_RGBA_8888;
|
||||
result = NO_ERROR;
|
||||
} else {
|
||||
result = NO_MEMORY;
|
||||
{
|
||||
// in this block we render the screenshot into the
|
||||
// CpuConsumer using glReadPixels from our GLConsumer,
|
||||
// Some older drivers don't support the GL->CPU path so
|
||||
// have to wrap it with a CPU->CPU path, which is what
|
||||
// glReadPixels essentially is
|
||||
|
||||
sp<Surface> sur = new Surface(producer);
|
||||
ANativeWindow* window = sur.get();
|
||||
ANativeWindowBuffer* buffer;
|
||||
void* vaddr;
|
||||
|
||||
if (native_window_api_connect(window,
|
||||
NATIVE_WINDOW_API_CPU) == NO_ERROR) {
|
||||
int err = 0;
|
||||
err = native_window_set_buffers_dimensions(window,
|
||||
reqWidth, reqHeight);
|
||||
err |= native_window_set_buffers_format(window,
|
||||
HAL_PIXEL_FORMAT_RGBA_8888);
|
||||
err |= native_window_set_usage(window,
|
||||
GRALLOC_USAGE_SW_READ_OFTEN |
|
||||
GRALLOC_USAGE_SW_WRITE_OFTEN);
|
||||
|
||||
if (err == NO_ERROR) {
|
||||
if (native_window_dequeue_buffer_and_wait(window,
|
||||
&buffer) == NO_ERROR) {
|
||||
sp<GraphicBuffer> buf =
|
||||
static_cast<GraphicBuffer*>(buffer);
|
||||
if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
|
||||
&vaddr) == NO_ERROR) {
|
||||
if (buffer->stride != int(reqWidth)) {
|
||||
// we're unlucky here, glReadPixels is
|
||||
// not able to deal with a stride not
|
||||
// equal to the width.
|
||||
uint32_t* tmp = new uint32_t[reqWidth*reqHeight];
|
||||
if (tmp != NULL) {
|
||||
glReadPixels(0, 0, reqWidth, reqHeight,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, tmp);
|
||||
for (size_t y=0 ; y<reqHeight ; y++) {
|
||||
memcpy((uint32_t*)vaddr + y*buffer->stride,
|
||||
tmp + y*reqWidth, reqWidth*4);
|
||||
}
|
||||
delete [] tmp;
|
||||
}
|
||||
} else {
|
||||
glReadPixels(0, 0, reqWidth, reqHeight,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, vaddr);
|
||||
}
|
||||
buf->unlock();
|
||||
}
|
||||
window->queueBuffer(window, buffer, -1);
|
||||
}
|
||||
}
|
||||
native_window_api_disconnect(window, NATIVE_WINDOW_API_CPU);
|
||||
}
|
||||
} else {
|
||||
result = NO_MEMORY;
|
||||
}
|
||||
|
||||
// back to main framebuffer
|
||||
|
@ -2742,63 +2784,6 @@ status_t SurfaceFlinger::captureScreenImplLocked(
|
|||
return result;
|
||||
}
|
||||
|
||||
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
|
||||
sp<IMemoryHeap>* heap,
|
||||
uint32_t* outWidth, uint32_t* outHeight, PixelFormat* outFormat,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
{
|
||||
if (CC_UNLIKELY(display == 0))
|
||||
return BAD_VALUE;
|
||||
|
||||
class MessageCaptureScreen : public MessageBase {
|
||||
SurfaceFlinger* flinger;
|
||||
sp<IBinder> display;
|
||||
sp<IMemoryHeap>* heap;
|
||||
uint32_t* outWidth;
|
||||
uint32_t* outHeight;
|
||||
PixelFormat* outFormat;
|
||||
uint32_t reqWidth;
|
||||
uint32_t reqHeight;
|
||||
uint32_t minLayerZ;
|
||||
uint32_t maxLayerZ;
|
||||
status_t result;
|
||||
public:
|
||||
MessageCaptureScreen(SurfaceFlinger* flinger,
|
||||
const sp<IBinder>& display, sp<IMemoryHeap>* heap,
|
||||
uint32_t* outWidth, uint32_t* outHeight, PixelFormat* outFormat,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
: flinger(flinger), display(display), heap(heap),
|
||||
outWidth(outWidth), outHeight(outHeight), outFormat(outFormat),
|
||||
reqWidth(reqWidth), reqHeight(reqHeight),
|
||||
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
|
||||
result(PERMISSION_DENIED)
|
||||
{
|
||||
}
|
||||
status_t getResult() const {
|
||||
return result;
|
||||
}
|
||||
virtual bool handler() {
|
||||
Mutex::Autolock _l(flinger->mStateLock);
|
||||
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
|
||||
result = flinger->captureScreenImplLocked(hw, heap,
|
||||
outWidth, outHeight, outFormat,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
sp<MessageBase> msg = new MessageCaptureScreen(this, display, heap,
|
||||
outWidth, outHeight, outFormat,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
status_t res = postMessageSync(msg);
|
||||
if (res == NO_ERROR) {
|
||||
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
SurfaceFlinger::LayerVector::LayerVector() {
|
||||
|
|
|
@ -185,14 +185,10 @@ private:
|
|||
virtual bool authenticateSurfaceTexture(
|
||||
const sp<IGraphicBufferProducer>& bufferProducer) const;
|
||||
virtual sp<IDisplayEventConnection> createDisplayEventConnection();
|
||||
virtual status_t captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* heap,
|
||||
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||
uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
|
||||
uint32_t maxLayerZ);
|
||||
virtual status_t captureScreen(const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ);
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer);
|
||||
// called when screen needs to turn off
|
||||
virtual void blank(const sp<IBinder>& display);
|
||||
// called when screen is turning back on
|
||||
|
@ -297,17 +293,17 @@ private:
|
|||
|
||||
status_t captureScreenImplLocked(
|
||||
const sp<const DisplayDevice>& hw,
|
||||
sp<IMemoryHeap>* heap,
|
||||
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||
uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
|
||||
uint32_t maxLayerZ);
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ);
|
||||
|
||||
status_t captureScreenImplLocked(
|
||||
status_t captureScreenImplCpuConsumerLocked(
|
||||
const sp<const DisplayDevice>& hw,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* EGL
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue