Loading include/surfaceflinger/ISurfaceComposer.h +9 −1 Original line number Diff line number Diff line Loading @@ -110,6 +110,13 @@ public: */ virtual void bootFinished() = 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(DisplayID dpy, sp<IMemoryHeap>* heap, uint32_t* width, uint32_t* height, PixelFormat* format) = 0; /* Signal surfaceflinger that there might be some work to do * This is an ASYNCHRONOUS call. */ Loading @@ -133,7 +140,8 @@ public: SET_ORIENTATION, FREEZE_DISPLAY, UNFREEZE_DISPLAY, SIGNAL SIGNAL, CAPTURE_SCREEN }; virtual status_t onTransact( uint32_t code, Loading libs/surfaceflinger_client/ISurfaceComposer.cpp +28 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,21 @@ public: remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } virtual status_t captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, uint32_t* width, uint32_t* height, PixelFormat* format) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeInt32(dpy); remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); *heap = interface_cast<IMemoryHeap>(reply.readStrongBinder()); *width = reply.readInt32(); *height = reply.readInt32(); *format = reply.readInt32(); return reply.readInt32(); } virtual void signal() const { Parcel data, reply; Loading Loading @@ -190,6 +205,19 @@ status_t BnSurfaceComposer::onTransact( sp<IBinder> b = getCblk()->asBinder(); reply->writeStrongBinder(b); } break; case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); DisplayID dpy = data.readInt32(); sp<IMemoryHeap> heap; uint32_t w, h; PixelFormat f; status_t res = captureScreen(dpy, &heap, &w, &h, &f); reply->writeStrongBinder(heap->asBinder()); reply->writeInt32(w); reply->writeInt32(h); reply->writeInt32(f); reply->writeInt32(res); } break; default: return BBinder::onTransact(code, data, reply, flags); } Loading services/surfaceflinger/GLExtensions.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,10 @@ void GLExtensions::initWithGLStrings( // hack for Adreno 200 mHaveTextureExternal = true; } if (hasExtension("GL_OES_framebuffer_object")) { mHaveFramebufferObject = true; } } bool GLExtensions::hasExtension(char const* extension) const Loading services/surfaceflinger/GLExtensions.h +5 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ class GLExtensions : public Singleton<GLExtensions> bool mHaveTextureExternal : 1; bool mHaveNpot : 1; bool mHaveDirectTexture : 1; bool mHaveFramebufferObject : 1; String8 mVendor; String8 mRenderer; Loading Loading @@ -66,6 +67,10 @@ public: return mHaveDirectTexture; } inline bool haveFramebufferObject() const { return mHaveFramebufferObject; } void initWithGLStrings( GLubyte const* vendor, GLubyte const* renderer, Loading services/surfaceflinger/SurfaceFlinger.cpp +149 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ SurfaceFlinger::SurfaceFlinger() mBootTime(systemTime()), mHardwareTest("android.permission.HARDWARE_TEST"), mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"), mReadFramebuffer("android.permission.READ_FRAME_BUFFER"), mDump("android.permission.DUMP"), mVisibleRegionsDirty(false), mDeferReleaseConsole(false), Loading Loading @@ -1465,8 +1466,23 @@ status_t SurfaceFlinger::onTransact( "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } break; } case CAPTURE_SCREEN: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_GRAPHICS) && !mReadFramebuffer.check(pid, uid)) { LOGE("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); if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { CHECK_INTERFACE(ISurfaceComposer, data, reply); Loading Loading @@ -1530,6 +1546,139 @@ status_t SurfaceFlinger::onTransact( // --------------------------------------------------------------------------- status_t SurfaceFlinger::captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, uint32_t* width, uint32_t* height, PixelFormat* format) { // only one display supported for now if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) return BAD_VALUE; if (!GLExtensions::getInstance().haveFramebufferObject()) return INVALID_OPERATION; class MessageCaptureScreen : public MessageBase { SurfaceFlinger* flinger; DisplayID dpy; sp<IMemoryHeap>* heap; uint32_t* w; uint32_t* h; PixelFormat* f; status_t result; public: MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy, sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f) : flinger(flinger), dpy(dpy), heap(heap), w(w), h(h), f(f), result(PERMISSION_DENIED) { } status_t getResult() const { return result; } virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); // if we have secure windows, never allow the screen capture if (flinger->mSecureFrameBuffer) return true; // make sure to clear all GL error flags while ( glGetError() != GL_NO_ERROR ) ; // get screen geometry const DisplayHardware& hw(flinger->graphicPlane(dpy).displayHardware()); const uint32_t sw = hw.getWidth(); const uint32_t sh = hw.getHeight(); const Region screenBounds(hw.bounds()); const size_t size = sw * sh * 4; // create a FBO GLuint name, tname; glGenRenderbuffersOES(1, &tname); glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh); glGenFramebuffersOES(1, &name); glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); if (status == GL_FRAMEBUFFER_COMPLETE_OES) { // invert everything, b/c glReadPixel() below will invert the FB glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrthof(0, sw, 0, sh, 0, 1); glMatrixMode(GL_MODELVIEW); // redraw the screen entirely... glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); const Vector< sp<LayerBase> >& layers( flinger->mVisibleLayersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer(layers[i]); if (!strcmp(layer->getTypeId(), "LayerBuffer")) { // we cannot render LayerBuffer because it doens't // use OpenGL, and won't show-up in the FBO. continue; } layer->draw(screenBounds); } glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); // check for errors and return screen capture if (glGetError() != GL_NO_ERROR) { // error while rendering result = INVALID_OPERATION; } else { // 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) { // capture the screen with 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; } } } else { result = BAD_VALUE; } // release FBO resources glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); glDeleteRenderbuffersOES(1, &tname); glDeleteFramebuffersOES(1, &name); return true; } }; sp<MessageBase> msg = new MessageCaptureScreen(this, dpy, heap, width, height, format); status_t res = postMessageSync(msg); if (res == NO_ERROR) { res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); } return res; } // --------------------------------------------------------------------------- sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const { sp<Layer> result; Loading Loading
include/surfaceflinger/ISurfaceComposer.h +9 −1 Original line number Diff line number Diff line Loading @@ -110,6 +110,13 @@ public: */ virtual void bootFinished() = 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(DisplayID dpy, sp<IMemoryHeap>* heap, uint32_t* width, uint32_t* height, PixelFormat* format) = 0; /* Signal surfaceflinger that there might be some work to do * This is an ASYNCHRONOUS call. */ Loading @@ -133,7 +140,8 @@ public: SET_ORIENTATION, FREEZE_DISPLAY, UNFREEZE_DISPLAY, SIGNAL SIGNAL, CAPTURE_SCREEN }; virtual status_t onTransact( uint32_t code, Loading
libs/surfaceflinger_client/ISurfaceComposer.cpp +28 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,21 @@ public: remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } virtual status_t captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, uint32_t* width, uint32_t* height, PixelFormat* format) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeInt32(dpy); remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); *heap = interface_cast<IMemoryHeap>(reply.readStrongBinder()); *width = reply.readInt32(); *height = reply.readInt32(); *format = reply.readInt32(); return reply.readInt32(); } virtual void signal() const { Parcel data, reply; Loading Loading @@ -190,6 +205,19 @@ status_t BnSurfaceComposer::onTransact( sp<IBinder> b = getCblk()->asBinder(); reply->writeStrongBinder(b); } break; case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); DisplayID dpy = data.readInt32(); sp<IMemoryHeap> heap; uint32_t w, h; PixelFormat f; status_t res = captureScreen(dpy, &heap, &w, &h, &f); reply->writeStrongBinder(heap->asBinder()); reply->writeInt32(w); reply->writeInt32(h); reply->writeInt32(f); reply->writeInt32(res); } break; default: return BBinder::onTransact(code, data, reply, flags); } Loading
services/surfaceflinger/GLExtensions.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,10 @@ void GLExtensions::initWithGLStrings( // hack for Adreno 200 mHaveTextureExternal = true; } if (hasExtension("GL_OES_framebuffer_object")) { mHaveFramebufferObject = true; } } bool GLExtensions::hasExtension(char const* extension) const Loading
services/surfaceflinger/GLExtensions.h +5 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ class GLExtensions : public Singleton<GLExtensions> bool mHaveTextureExternal : 1; bool mHaveNpot : 1; bool mHaveDirectTexture : 1; bool mHaveFramebufferObject : 1; String8 mVendor; String8 mRenderer; Loading Loading @@ -66,6 +67,10 @@ public: return mHaveDirectTexture; } inline bool haveFramebufferObject() const { return mHaveFramebufferObject; } void initWithGLStrings( GLubyte const* vendor, GLubyte const* renderer, Loading
services/surfaceflinger/SurfaceFlinger.cpp +149 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ SurfaceFlinger::SurfaceFlinger() mBootTime(systemTime()), mHardwareTest("android.permission.HARDWARE_TEST"), mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"), mReadFramebuffer("android.permission.READ_FRAME_BUFFER"), mDump("android.permission.DUMP"), mVisibleRegionsDirty(false), mDeferReleaseConsole(false), Loading Loading @@ -1465,8 +1466,23 @@ status_t SurfaceFlinger::onTransact( "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } break; } case CAPTURE_SCREEN: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_GRAPHICS) && !mReadFramebuffer.check(pid, uid)) { LOGE("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); if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { CHECK_INTERFACE(ISurfaceComposer, data, reply); Loading Loading @@ -1530,6 +1546,139 @@ status_t SurfaceFlinger::onTransact( // --------------------------------------------------------------------------- status_t SurfaceFlinger::captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, uint32_t* width, uint32_t* height, PixelFormat* format) { // only one display supported for now if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) return BAD_VALUE; if (!GLExtensions::getInstance().haveFramebufferObject()) return INVALID_OPERATION; class MessageCaptureScreen : public MessageBase { SurfaceFlinger* flinger; DisplayID dpy; sp<IMemoryHeap>* heap; uint32_t* w; uint32_t* h; PixelFormat* f; status_t result; public: MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy, sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f) : flinger(flinger), dpy(dpy), heap(heap), w(w), h(h), f(f), result(PERMISSION_DENIED) { } status_t getResult() const { return result; } virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); // if we have secure windows, never allow the screen capture if (flinger->mSecureFrameBuffer) return true; // make sure to clear all GL error flags while ( glGetError() != GL_NO_ERROR ) ; // get screen geometry const DisplayHardware& hw(flinger->graphicPlane(dpy).displayHardware()); const uint32_t sw = hw.getWidth(); const uint32_t sh = hw.getHeight(); const Region screenBounds(hw.bounds()); const size_t size = sw * sh * 4; // create a FBO GLuint name, tname; glGenRenderbuffersOES(1, &tname); glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh); glGenFramebuffersOES(1, &name); glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); if (status == GL_FRAMEBUFFER_COMPLETE_OES) { // invert everything, b/c glReadPixel() below will invert the FB glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrthof(0, sw, 0, sh, 0, 1); glMatrixMode(GL_MODELVIEW); // redraw the screen entirely... glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); const Vector< sp<LayerBase> >& layers( flinger->mVisibleLayersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer(layers[i]); if (!strcmp(layer->getTypeId(), "LayerBuffer")) { // we cannot render LayerBuffer because it doens't // use OpenGL, and won't show-up in the FBO. continue; } layer->draw(screenBounds); } glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); // check for errors and return screen capture if (glGetError() != GL_NO_ERROR) { // error while rendering result = INVALID_OPERATION; } else { // 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) { // capture the screen with 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; } } } else { result = BAD_VALUE; } // release FBO resources glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); glDeleteRenderbuffersOES(1, &tname); glDeleteFramebuffersOES(1, &name); return true; } }; sp<MessageBase> msg = new MessageCaptureScreen(this, dpy, heap, width, height, format); status_t res = postMessageSync(msg); if (res == NO_ERROR) { res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); } return res; } // --------------------------------------------------------------------------- sp<Layer> SurfaceFlinger::getLayer(const sp<ISurface>& sur) const { sp<Layer> result; Loading