Merge "Several fixes in AudioDumpInterface:" into kraken
diff --git a/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/camera/tests/CameraServiceTest/CameraServiceTest.cpp
index 41670af..cb69534 100644
--- a/camera/tests/CameraServiceTest/CameraServiceTest.cpp
+++ b/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -298,6 +298,7 @@
     virtual sp<OverlayRef> createOverlay(
             uint32_t w, uint32_t h, int32_t format, int32_t orientation);
     virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage);
+    virtual status_t setBufferCount(int bufferCount);
 
     // new functions
     void clearStat();
@@ -339,6 +340,11 @@
     return NULL;
 }
 
+status_t MSurface::setBufferCount(int bufferCount) {
+    INFO(__func__);
+    return NULL;
+}
+
 void MSurface::clearStat() {
     Mutex::Autolock _l(mLock);
     registerBuffersCount = 0;
diff --git a/common/java/com/android/common/GoogleLogTags.logtags b/common/java/com/android/common/GoogleLogTags.logtags
index a5c9bb0..f848ddf 100644
--- a/common/java/com/android/common/GoogleLogTags.logtags
+++ b/common/java/com/android/common/GoogleLogTags.logtags
@@ -80,7 +80,7 @@
 204004 gtalk_heartbeat_reset (interval_and_nt|1),(ip|3)
 
 # This event is logged when an Rmq v2 packet is sent or received.
-204005 push_messaging (packet_type|1),(persistent_id|3),(stream_id|1),(last_stream_id|1)
+204005 c2dm (packet_type|1),(persistent_id|3),(stream_id|1),(last_stream_id|1)
 
 #####
 # Google Login Service and Setup Wizard
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index 2504d39..c23832d 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -129,7 +129,7 @@
 
 // ----------------------------------------------------------------------------
 
-// 4 KB max
+// 32 KB max
 class SharedClient
 {
 public:
@@ -166,7 +166,7 @@
 protected:
     SharedClient* const mSharedClient;
     SharedBufferStack* const mSharedStack;
-    const int mNumBuffers;
+    int mNumBuffers;
     const int mIdentity;
     int32_t computeTail() const;
 
@@ -217,6 +217,7 @@
     bool needNewBuffer(int buffer) const;
     status_t setDirtyRegion(int buffer, const Region& reg);
     status_t setCrop(int buffer, const Rect& reg);
+    status_t setBufferCount(int bufferCount);
     
 private:
     friend struct Condition;
@@ -269,13 +270,61 @@
     status_t reallocate();
     status_t assertReallocate(int buffer);
     int32_t getQueuedCount() const;
-    
     Region getDirtyRegion(int buffer) const;
 
+    status_t resize(int newNumBuffers);
+
     SharedBufferStack::Statistics getStats() const;
     
 
 private:
+    /*
+     * BufferList is basically a fixed-capacity sorted-vector of
+     * unsigned 5-bits ints using a 32-bits int as storage.
+     * it has efficient iterators to find items in the list and not in the list.
+     */
+    class BufferList {
+        size_t mCapacity;
+        uint32_t mList;
+    public:
+        BufferList(size_t c = NUM_BUFFER_MAX) : mCapacity(c), mList(0) { }
+        status_t add(int value);
+        status_t remove(int value);
+
+        class const_iterator {
+            friend class BufferList;
+            uint32_t mask, curr;
+            const_iterator(uint32_t mask) :
+                mask(mask), curr(31 - __builtin_clz(mask)) { }
+        public:
+            inline bool operator == (const const_iterator& rhs) const {
+                return mask == rhs.mask;
+            }
+            inline bool operator != (const const_iterator& rhs) const {
+                return mask != rhs.mask;
+            }
+            inline int operator *() const { return curr; }
+            inline const const_iterator& operator ++(int) {
+                mask &= ~curr;
+                curr = 31 - __builtin_clz(mask);
+                return *this;
+            }
+        };
+
+        inline const_iterator begin() const {
+            return const_iterator(mList);
+        }
+        inline const_iterator end() const   {
+            return const_iterator(0);
+        }
+        inline const_iterator free_begin() const {
+            uint32_t mask = (1 << (32-mCapacity)) - 1;
+            return const_iterator( ~(mList | mask) );
+        }
+    };
+
+    BufferList mBufferList;
+
     struct UnlockUpdate : public UpdateBase {
         const int lockedBuffer;
         inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h
index 472f759..9476686 100644
--- a/include/surfaceflinger/ISurface.h
+++ b/include/surfaceflinger/ISurface.h
@@ -47,12 +47,14 @@
         POST_BUFFER, // one-way transaction
         CREATE_OVERLAY,
         REQUEST_BUFFER,
+        SET_BUFFER_COUNT,
     };
 
 public: 
     DECLARE_META_INTERFACE(Surface);
 
     virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) = 0; 
+    virtual status_t setBufferCount(int bufferCount) = 0;
     
     class BufferHeap {
     public:
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 7ab3a00..973780f 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -217,6 +217,7 @@
     int  connect(int api);
     int  disconnect(int api);
     int  crop(Rect const* rect);
+    int  setBufferCount(int bufferCount);
 
     /*
      *  private stuff...
diff --git a/include/utils/ZipFileCRO.h b/include/utils/ZipFileCRO.h
index 30e0036..e38bf66 100644
--- a/include/utils/ZipFileCRO.h
+++ b/include/utils/ZipFileCRO.h
@@ -47,8 +47,8 @@
         const char* fileName);
 
 extern bool ZipFileCRO_getEntryInfo(ZipFileCRO zip, ZipEntryCRO entry,
-        int* pMethod, long* pUncompLen,
-        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32);
+        int* pMethod, size_t* pUncompLen,
+        size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32);
 
 extern bool ZipFileCRO_uncompressEntry(ZipFileCRO zip, ZipEntryCRO entry, int fd);
 
diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h
index 51c4f2f..97d31f4 100644
--- a/include/utils/ZipFileRO.h
+++ b/include/utils/ZipFileRO.h
@@ -58,14 +58,19 @@
 class ZipFileRO {
 public:
     ZipFileRO()
-        : mFd(-1), mFileMap(NULL), mHashTableSize(-1), mHashTable(NULL)
+        : mFd(-1), mFileName(NULL), mFileLength(-1),
+          mDirectoryMap(NULL),
+          mNumEntries(-1), mDirectoryOffset(-1),
+          mHashTableSize(-1), mHashTable(NULL)
         {}
     ~ZipFileRO() {
         free(mHashTable);
-        if (mFileMap)
-            mFileMap->release();
+        if (mDirectoryMap)
+            mDirectoryMap->release();
         if (mFd >= 0)
             close(mFd);
+        if (mFileName)
+            free(mFileName);
     }
 
     /*
@@ -118,8 +123,8 @@
      * Returns "false" if "entry" is bogus or if the data in the Zip file
      * appears to be bad.
      */
-    bool getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen,
-        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const;
+    bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
+        size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const;
 
     /*
      * Create a new FileMap object that maps a subset of the archive.  For
@@ -155,13 +160,13 @@
      * Utility function: uncompress deflated data, buffer to buffer.
      */
     static bool inflateBuffer(void* outBuf, const void* inBuf,
-        long uncompLen, long compLen);
+        size_t uncompLen, size_t compLen);
 
     /*
      * Utility function: uncompress deflated data, buffer to fd.
      */
     static bool inflateBuffer(int fd, const void* inBuf,
-        long uncompLen, long compLen);
+        size_t uncompLen, size_t compLen);
 
     /*
      * Some basic functions for raw data manipulation.  "LE" means
@@ -179,6 +184,9 @@
     ZipFileRO(const ZipFileRO& src);
     ZipFileRO& operator=(const ZipFileRO& src);
 
+    /* locate and parse the central directory */
+    bool mapCentralDirectory(void);
+
     /* parse the archive, prepping internal structures */
     bool parseZipArchive(void);
 
@@ -203,12 +211,21 @@
     /* open Zip archive */
     int         mFd;
 
+    /* zip file name */
+    char*       mFileName;
+
+    /* length of file */
+    size_t      mFileLength;
+
     /* mapped file */
-    FileMap*    mFileMap;
+    FileMap*    mDirectoryMap;
 
     /* number of entries in the Zip archive */
     int         mNumEntries;
 
+    /* CD directory offset in the Zip archive */
+    off_t       mDirectoryOffset;
+
     /*
      * We know how many entries are in the Zip archive, so we have a
      * fixed-size hash table.  We probe for an empty slot.
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 86eb78d..b8a0630 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -13,6 +13,7 @@
     LayerDim.cpp \
     MessageQueue.cpp \
     SurfaceFlinger.cpp \
+    TextureManager.cpp \
     Tokenizer.cpp \
     Transform.cpp
 
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index d979f00..af89e9a 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -125,7 +125,6 @@
     EGLint numConfigs=0;
     EGLSurface surface;
     EGLContext context;
-    mFlags = CACHED_BUFFERS;
 
     // TODO: all the extensions below should be queried through
     // eglGetProcAddress().
@@ -253,15 +252,6 @@
     LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
     LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
 
-#if 0
-    // for drivers that don't have proper support for flushing cached buffers
-    // on gralloc unlock, uncomment this block and test for the specific
-    // renderer substring
-    if (strstr(gl_renderer, "<some vendor string>")) {
-        LOGD("Assuming uncached graphics buffers.");
-        mFlags &= ~CACHED_BUFFERS;
-    }
-#endif
 
     if (strstr(gl_extensions, "GL_ARB_texture_non_power_of_two")) {
         mFlags |= NPOT_EXTENSION;
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index 897a6ed..ebd7c42 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -50,7 +50,6 @@
         PARTIAL_UPDATES         = 0x00020000,   // video driver feature
         SLOW_CONFIG             = 0x00040000,   // software
         SWAP_RECTANGLE          = 0x00080000,
-        CACHED_BUFFERS          = 0x00100000
     };
 
     DisplayHardware(
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index e6658fa..1fe997d 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -48,41 +48,48 @@
 // ---------------------------------------------------------------------------
 
 Layer::Layer(SurfaceFlinger* flinger, DisplayID display, 
-        const sp<Client>& c, int32_t i)
-    :   LayerBaseClient(flinger, display, c, i),
+        const sp<Client>& client, int32_t i)
+    :   LayerBaseClient(flinger, display, client, i),
+        lcblk(NULL),
         mSecure(false),
-        mNoEGLImageForSwBuffers(false),
         mNeedsBlending(true),
-        mNeedsDithering(false)
+        mNeedsDithering(false),
+        mTextureManager(mFlags),
+        mBufferManager(mTextureManager)
 {
     // no OpenGL operation is possible here, since we might not be
     // in the OpenGL thread.
-    mFrontBufferIndex = lcblk->getFrontBuffer();
+    lcblk = new SharedBufferServer(
+            client->ctrlblk, i, mBufferManager.getBufferCount(),
+            getIdentity());
+
+   mBufferManager.setActiveBufferIndex( lcblk->getFrontBuffer() );
 }
 
 Layer::~Layer()
 {
     destroy();
     // the actual buffers will be destroyed here
+    delete lcblk;
+}
+
+// called with SurfaceFlinger::mStateLock as soon as the layer is entered
+// in the purgatory list
+void Layer::onRemoved()
+{
+    // wake up the condition
+    lcblk->setStatus(NO_INIT);
 }
 
 void Layer::destroy()
 {
-    for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
-        if (mTextures[i].name != -1U) {
-            glDeleteTextures(1, &mTextures[i].name);
-            mTextures[i].name = -1U;
-        }
-        if (mTextures[i].image != EGL_NO_IMAGE_KHR) {
-            EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-            eglDestroyImageKHR(dpy, mTextures[i].image);
-            mTextures[i].image = EGL_NO_IMAGE_KHR;
-        }
-        Mutex::Autolock _l(mLock);
-        mBuffers[i].clear();
-        mWidth = mHeight = 0;
-    }
+    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+    mBufferManager.destroy(dpy);
+
     mSurface.clear();
+
+    Mutex::Autolock _l(mLock);
+    mWidth = mHeight = 0;
 }
 
 sp<LayerBaseClient::Surface> Layer::createSurface() const
@@ -126,24 +133,19 @@
     mHeight = h;
     mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
     mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
-    mNoEGLImageForSwBuffers = !(hwFlags & DisplayHardware::CACHED_BUFFERS);
 
     // we use the red index
     int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
     int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);
     mNeedsDithering = layerRedsize > displayRedSize;
 
-    for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
-        mBuffers[i] = new GraphicBuffer();
-    }
     mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
     return NO_ERROR;
 }
 
 void Layer::reloadTexture(const Region& dirty)
 {
-    Mutex::Autolock _l(mLock);
-    sp<GraphicBuffer> buffer(getFrontBufferLocked());
+    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
     if (buffer == NULL) {
         // this situation can happen if we ran out of memory for instance.
         // not much we can do. continue to use whatever texture was bound
@@ -151,118 +153,24 @@
         return;
     }
 
-    const int index = mFrontBufferIndex;
-
-    // create the new texture name if needed
-    if (UNLIKELY(mTextures[index].name == -1U)) {
-        mTextures[index].name = createTexture();
-        mTextures[index].width = 0;
-        mTextures[index].height = 0;
-    }
-
 #ifdef EGL_ANDROID_image_native_buffer
     if (mFlags & DisplayHardware::DIRECT_TEXTURE) {
-        if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) {
-            if (mTextures[index].dirty) {
-                if (initializeEglImage(buffer, &mTextures[index]) != NO_ERROR) {
-                    // not sure what we can do here...
-                    mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
-                    goto slowpath;
-                }
-            }
-        } else {
-            if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width ||
-                    mHybridBuffer->height != buffer->height)) {
-                mHybridBuffer.clear();
-                mHybridBuffer = new GraphicBuffer(
-                        buffer->width, buffer->height, buffer->format,
-                        GraphicBuffer::USAGE_SW_WRITE_OFTEN |
-                        GraphicBuffer::USAGE_HW_TEXTURE);
-                if (initializeEglImage(
-                        mHybridBuffer, &mTextures[0]) != NO_ERROR) {
-                    // not sure what we can do here...
-                    mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
-                    mHybridBuffer.clear();
-                    goto slowpath;
-                }
-            }
-
-            GGLSurface t;
-            status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
-            LOGE_IF(res, "error %d (%s) locking buffer %p",
-                    res, strerror(res), buffer.get());
-            if (res == NO_ERROR) {
-                Texture* const texture(&mTextures[0]);
-
-                glBindTexture(GL_TEXTURE_2D, texture->name);
-
-                sp<GraphicBuffer> buf(mHybridBuffer);
-                void* vaddr;
-                res = buf->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &vaddr);
-                if (res == NO_ERROR) {
-                    int bpp = 0;
-                    switch (t.format) {
-                    case HAL_PIXEL_FORMAT_RGB_565:
-                    case HAL_PIXEL_FORMAT_RGBA_4444:
-                        bpp = 2;
-                        break;
-                    case HAL_PIXEL_FORMAT_RGBA_8888:
-                    case HAL_PIXEL_FORMAT_RGBX_8888:
-                        bpp = 4;
-                        break;
-                    default:
-                        if (isSupportedYuvFormat(t.format)) {
-                            // just show the Y plane of YUV buffers
-                            bpp = 1;
-                            break;
-                        }
-                        // oops, we don't handle this format!
-                        LOGE("layer %p, texture=%d, using format %d, which is not "
-                                "supported by the GL", this, texture->name, t.format);
-                    }
-                    if (bpp) {
-                        const Rect bounds(dirty.getBounds());
-                        size_t src_stride = t.stride;
-                        size_t dst_stride = buf->stride;
-                        if (src_stride == dst_stride &&
-                            bounds.width() == t.width &&
-                            bounds.height() == t.height)
-                        {
-                            memcpy(vaddr, t.data, t.height * t.stride * bpp);
-                        } else {
-                            GLubyte const * src = t.data +
-                                (bounds.left + bounds.top * src_stride) * bpp;
-                            GLubyte * dst = (GLubyte *)vaddr +
-                                (bounds.left + bounds.top * dst_stride) * bpp;
-                            const size_t length = bounds.width() * bpp;
-                            size_t h = bounds.height();
-                            src_stride *= bpp;
-                            dst_stride *= bpp;
-                            while (h--) {
-                                memcpy(dst, src, length);
-                                dst += dst_stride;
-                                src += src_stride;
-                            }
-                        }
-                    }
-                    buf->unlock();
-                }
-                buffer->unlock();
-            }
+        EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+        if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) {
+            // not sure what we can do here...
+            mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
+            goto slowpath;
         }
     } else
 #endif
     {
 slowpath:
-        for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
-            mTextures[i].image = EGL_NO_IMAGE_KHR;
-        }
         GGLSurface t;
         status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
         LOGE_IF(res, "error %d (%s) locking buffer %p",
                 res, strerror(res), buffer.get());
         if (res == NO_ERROR) {
-            loadTexture(&mTextures[0], dirty, t);
+            mBufferManager.loadTexture(dirty, t);
             buffer->unlock();
         }
     }
@@ -270,11 +178,8 @@
 
 void Layer::onDraw(const Region& clip) const
 {
-    int index = mFrontBufferIndex;
-    if (mTextures[index].image == EGL_NO_IMAGE_KHR)
-        index = 0;
-    GLuint textureName = mTextures[index].name;
-    if (UNLIKELY(textureName == -1LU)) {
+    Texture tex(mBufferManager.getActiveTexture());
+    if (tex.name == -1LU) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
         // SurfaceView because the WindowManager can't know when the client
@@ -300,7 +205,31 @@
         }
         return;
     }
-    drawWithOpenGL(clip, mTextures[index]);
+    drawWithOpenGL(clip, tex);
+}
+
+
+status_t Layer::setBufferCount(int bufferCount)
+{
+    // this ensures our client doesn't go away while we're accessing
+    // the shared area.
+    sp<Client> ourClient(client.promote());
+    if (ourClient == 0) {
+        // oops, the client is already gone
+        return DEAD_OBJECT;
+    }
+
+    status_t err;
+
+    // FIXME: resize() below is NOT thread-safe, we need to synchronize
+    // the users of lcblk in our process (ie: retire), and we assume the
+    // client is not mucking with the SharedStack, which is only enforced
+    // by construction, therefore we need to protect ourselves against
+    // buggy and malicious client (as always)
+
+    err = lcblk->resize(bufferCount);
+
+    return err;
 }
 
 sp<GraphicBuffer> Layer::requestBuffer(int index, int usage)
@@ -337,15 +266,7 @@
         Mutex::Autolock _l(mLock);
         w = mWidth;
         h = mHeight;
-        buffer = mBuffers[index];
-        
-        // destroy() could have been called before we get here, we log it
-        // because it's uncommon, and the code below should handle it
-        LOGW_IF(buffer==0, 
-                "mBuffers[%d] is null (mWidth=%d, mHeight=%d)",
-                index, w, h);
-        
-        mBuffers[index].clear();
+        buffer = mBufferManager.detachBuffer(index);
     }
 
     const uint32_t effectiveUsage = getEffectiveUsage(usage);
@@ -373,10 +294,7 @@
     if (err == NO_ERROR && buffer->handle != 0) {
         Mutex::Autolock _l(mLock);
         if (mWidth && mHeight) {
-            // and we have new buffer
-            mBuffers[index] = buffer;
-            // texture is now dirty...
-            mTextures[index].dirty = true;
+            mBufferManager.attachBuffer(index, buffer);
         } else {
             // oops we got killed while we were allocating the buffer
             buffer.clear();
@@ -406,15 +324,8 @@
     } else {
         // it's allowed to modify the usage flags here, but generally
         // the requested flags should be honored.
-        if (mNoEGLImageForSwBuffers) {
-            if (usage & GraphicBuffer::USAGE_HW_MASK) {
-                // request EGLImage for h/w buffers only
-                usage |= GraphicBuffer::USAGE_HW_TEXTURE;
-            }
-        } else {
-            // request EGLImage for all buffers
-            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
-        }
+        // request EGLImage for all buffers
+        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
     }
     return usage;
 }
@@ -428,13 +339,10 @@
         (front.requested_h != temp.requested_h)) {
         // the size changed, we need to ask our client to request a new buffer
         LOGD_IF(DEBUG_RESIZE,
-                    "resize (layer=%p), requested (%dx%d), "
-                    "drawing (%d,%d), (%dx%d), (%dx%d)",
+                    "resize (layer=%p), requested (%dx%d), drawing (%d,%d)",
                     this, 
                     int(temp.requested_w), int(temp.requested_h),
-                    int(front.requested_w), int(front.requested_h),
-                    int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()),
-                    int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight()));
+                    int(front.requested_w), int(front.requested_h));
 
         // we're being resized and there is a freeze display request,
         // acquire a freeze lock, so that the screen stays put
@@ -486,22 +394,25 @@
 void Layer::lockPageFlip(bool& recomputeVisibleRegions)
 {
     ssize_t buf = lcblk->retireAndLock();
-    if (buf < NO_ERROR) {
-        //LOGW("nothing to retire (%s)", strerror(-buf));
-        // NOTE: here the buffer is locked because we will used 
+    if (buf == NOT_ENOUGH_DATA) {
+        // NOTE: This is not an error, it simply means there is nothing to
+        // retire. The buffer is locked because we will use it
         // for composition later in the loop
         return;
     }
 
-    // ouch, this really should never happen
-    if (uint32_t(buf)>=NUM_BUFFERS) {
+    if (buf < NO_ERROR) {
         LOGE("retireAndLock() buffer index (%d) out of range", buf);
         mPostedDirtyRegion.clear();
         return;
     }
 
     // we retired a buffer, which becomes the new front buffer
-    mFrontBufferIndex = buf;
+    if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
+        LOGE("retireAndLock() buffer index (%d) out of range", buf);
+        mPostedDirtyRegion.clear();
+        return;
+    }
 
     // get the dirty region
     sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
@@ -593,10 +504,9 @@
 
 void Layer::finishPageFlip()
 {
-    status_t err = lcblk->unlock( mFrontBufferIndex );
-    LOGE_IF(err!=NO_ERROR, 
-            "layer %p, buffer=%d wasn't locked!",
-            this, mFrontBufferIndex);
+    int buf = mBufferManager.getActiveBufferIndex();
+    status_t err = lcblk->unlock( buf );
+    LOGE_IF(err!=NO_ERROR, "layer %p, buffer=%d wasn't locked!", this, buf);
 }
 
 
@@ -633,6 +543,109 @@
 
 // ---------------------------------------------------------------------------
 
+Layer::BufferManager::BufferManager(TextureManager& tm)
+    : mTextureManager(tm), mActiveBuffer(0), mFailover(false)
+{
+}
+
+size_t Layer::BufferManager::getBufferCount() const {
+    return NUM_BUFFERS;
+}
+
+// only for debugging
+sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const {
+    return mBufferData[index].buffer;
+}
+
+status_t Layer::BufferManager::setActiveBufferIndex(size_t index) {
+    // TODO: need to validate 'index'
+    mActiveBuffer = index;
+    return NO_ERROR;
+}
+
+size_t Layer::BufferManager::getActiveBufferIndex() const {
+    return mActiveBuffer;
+}
+
+Texture Layer::BufferManager::getActiveTexture() const {
+    return mFailover ? mFailoverTexture : mBufferData[mActiveBuffer].texture;
+}
+
+sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const {
+    Mutex::Autolock _l(mLock);
+    return mBufferData[mActiveBuffer].buffer;
+}
+
+sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
+{
+    sp<GraphicBuffer> buffer;
+    Mutex::Autolock _l(mLock);
+    buffer = mBufferData[index].buffer;
+    mBufferData[index].buffer = 0;
+    return buffer;
+}
+
+status_t Layer::BufferManager::attachBuffer(size_t index,
+        const sp<GraphicBuffer>& buffer)
+{
+    Mutex::Autolock _l(mLock);
+    mBufferData[index].buffer = buffer;
+    mBufferData[index].texture.dirty = true;
+    return NO_ERROR;
+}
+
+status_t Layer::BufferManager::destroyTexture(Texture* tex, EGLDisplay dpy)
+{
+    if (tex->name != -1U) {
+        glDeleteTextures(1, &tex->name);
+        tex->name = -1U;
+    }
+    if (tex->image != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(dpy, tex->image);
+        tex->image = EGL_NO_IMAGE_KHR;
+    }
+    return NO_ERROR;
+}
+
+status_t Layer::BufferManager::destroy(EGLDisplay dpy)
+{
+    Mutex::Autolock _l(mLock);
+    for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
+        destroyTexture(&mBufferData[i].texture, dpy);
+        mBufferData[i].buffer = 0;
+    }
+    destroyTexture(&mFailoverTexture, dpy);
+    return NO_ERROR;
+}
+
+status_t Layer::BufferManager::initEglImage(EGLDisplay dpy,
+        const sp<GraphicBuffer>& buffer)
+{
+    size_t index = mActiveBuffer;
+    Texture& texture(mBufferData[index].texture);
+    status_t err = mTextureManager.initEglImage(&texture, dpy, buffer);
+    // if EGLImage fails, we switch to regular texture mode, and we
+    // free all resources associated with using EGLImages.
+    if (err == NO_ERROR) {
+        mFailover = false;
+        destroyTexture(&mFailoverTexture, dpy);
+    } else {
+        mFailover = true;
+        for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
+            destroyTexture(&mBufferData[i].texture, dpy);
+        }
+    }
+    return err;
+}
+
+status_t Layer::BufferManager::loadTexture(
+        const Region& dirty, const GGLSurface& t)
+{
+    return mTextureManager.loadTexture(&mFailoverTexture, dirty, t);
+}
+
+// ---------------------------------------------------------------------------
+
 Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
         SurfaceID id, const sp<Layer>& owner)
     : Surface(flinger, id, owner->getIdentity(), owner)
@@ -648,15 +661,21 @@
     sp<GraphicBuffer> buffer;
     sp<Layer> owner(getOwner());
     if (owner != 0) {
-        LOGE_IF(uint32_t(index)>=NUM_BUFFERS,
-                "getBuffer() index (%d) out of range", index);
-        if (uint32_t(index) < NUM_BUFFERS) {
-            buffer = owner->requestBuffer(index, usage);
-        }
+        buffer = owner->requestBuffer(index, usage);
     }
     return buffer;
 }
 
+status_t Layer::SurfaceLayer::setBufferCount(int bufferCount)
+{
+    status_t err = DEAD_OBJECT;
+    sp<Layer> owner(getOwner());
+    if (owner != 0) {
+        err = owner->setBufferCount(bufferCount);
+    }
+    return err;
+}
+
 // ---------------------------------------------------------------------------
 
 
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 98e30d7..80fbd6a 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -31,6 +31,7 @@
 
 #include "LayerBase.h"
 #include "Transform.h"
+#include "TextureManager.h"
 
 namespace android {
 
@@ -41,11 +42,13 @@
 
 // ---------------------------------------------------------------------------
 
-const size_t NUM_BUFFERS = 2;
-
 class Layer : public LayerBaseClient
 {
-public:    
+public:
+    // lcblk is (almost) only accessed from the main SF thread, in the places
+    // where it's not, a reference to Client must be held
+    SharedBufferServer*     lcblk;
+
                  Layer(SurfaceFlinger* flinger, DisplayID display,
                          const sp<Client>& client, int32_t i);
 
@@ -66,15 +69,14 @@
     virtual bool isSecure() const           { return mSecure; }
     virtual sp<Surface> createSurface() const;
     virtual status_t ditch();
+    virtual void onRemoved();
     
     // only for debugging
-    inline sp<GraphicBuffer> getBuffer(int i) const { return mBuffers[i]; }
+    inline sp<GraphicBuffer> getBuffer(int i) const { return mBufferManager.getBuffer(i); }
     // only for debugging
     inline const sp<FreezeLock>&  getFreezeLock() const { return mFreezeLock; }
     // only for debugging
     inline PixelFormat pixelFormat() const { return mFormat; }
-    // only for debugging
-    inline int getFrontBufferIndex() const { return mFrontBufferIndex; }
 
     virtual const char* getTypeId() const { return "Layer"; }
 
@@ -82,15 +84,12 @@
     virtual void dump(String8& result, char* scratch, size_t size) const;
 
 private:
-    inline sp<GraphicBuffer> getFrontBufferLocked() {
-        return mBuffers[mFrontBufferIndex];
-    }
- 
     void reloadTexture(const Region& dirty);
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
     sp<GraphicBuffer> requestBuffer(int index, int usage);
+    status_t setBufferCount(int bufferCount);
     void destroy();
 
     class SurfaceLayer : public LayerBaseClient::Surface {
@@ -100,6 +99,7 @@
         ~SurfaceLayer();
     private:
         virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
+        virtual status_t setBufferCount(int bufferCount);
         sp<Layer> getOwner() const {
             return static_cast<Layer*>(Surface::getOwner().get());
         }
@@ -109,22 +109,70 @@
     sp<Surface>             mSurface;
 
             bool            mSecure;
-            bool            mNoEGLImageForSwBuffers;
             int32_t         mFrontBufferIndex;
             bool            mNeedsBlending;
             bool            mNeedsDithering;
             Region          mPostedDirtyRegion;
             sp<FreezeLock>  mFreezeLock;
             PixelFormat     mFormat;
-            
-            // protected by mLock
-            sp<GraphicBuffer> mBuffers[NUM_BUFFERS];
-            Texture         mTextures[NUM_BUFFERS];
-            sp<GraphicBuffer> mHybridBuffer;
-            uint32_t        mWidth;
-            uint32_t        mHeight;
-            
-   mutable Mutex mLock;
+
+            class BufferManager {
+                static const size_t NUM_BUFFERS = 2;
+                struct BufferData {
+                    sp<GraphicBuffer>   buffer;
+                    Texture             texture;
+                };
+                mutable Mutex mLock;
+                BufferData          mBufferData[NUM_BUFFERS];
+                Texture             mFailoverTexture;
+                TextureManager&     mTextureManager;
+                ssize_t             mActiveBuffer;
+                bool                mFailover;
+                static status_t destroyTexture(Texture* tex, EGLDisplay dpy);
+
+            public:
+                BufferManager(TextureManager& tm);
+
+                size_t getBufferCount() const;
+
+                // detach/attach buffer from/to given index
+                sp<GraphicBuffer> detachBuffer(size_t index);
+                status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
+
+                // ----------------------------------------------
+                // must be called from GL thread
+
+                // set/get active buffer index
+                status_t setActiveBufferIndex(size_t index);
+                size_t getActiveBufferIndex() const;
+
+                // return the active buffer
+                sp<GraphicBuffer> getActiveBuffer() const;
+
+                // return the active texture (or fail-over)
+                Texture getActiveTexture() const;
+
+                // frees resources associated with all buffers
+                status_t destroy(EGLDisplay dpy);
+
+                // load bitmap data into the active buffer
+                status_t loadTexture(const Region& dirty, const GGLSurface& t);
+
+                // make active buffer an EGLImage if needed
+                status_t initEglImage(EGLDisplay dpy,
+                        const sp<GraphicBuffer>& buffer);
+
+                // ----------------------------------------------
+                // only for debugging
+                sp<GraphicBuffer> getBuffer(size_t index) const;
+            };
+
+            TextureManager mTextureManager;
+            BufferManager mBufferManager;
+
+            mutable Mutex mLock;
+            uint32_t    mWidth;
+            uint32_t    mHeight;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 48b0e47..63b9520 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -32,6 +32,7 @@
 #include "LayerBase.h"
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
+#include "TextureManager.h"
 
 
 namespace android {
@@ -340,18 +341,6 @@
     */
 }
 
-GLuint LayerBase::createTexture() const
-{
-    GLuint textureName = -1;
-    glGenTextures(1, &textureName);
-    glBindTexture(GL_TEXTURE_2D, textureName);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    return textureName;
-}
-
 void LayerBase::clearWithOpenGL(const Region& clip, GLclampx red,
                                 GLclampx green, GLclampx blue,
                                 GLclampx alpha) const
@@ -492,187 +481,6 @@
     }
 }
 
-bool LayerBase::isSupportedYuvFormat(int format) const
-{
-    switch (format) {
-        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-        case HAL_PIXEL_FORMAT_YCbCr_420_SP:
-        case HAL_PIXEL_FORMAT_YCbCr_422_P:
-        case HAL_PIXEL_FORMAT_YCbCr_420_P:
-        case HAL_PIXEL_FORMAT_YCbCr_422_I:
-        case HAL_PIXEL_FORMAT_YCbCr_420_I:
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            return true;
-    }
-    return false;
-}
-
-void LayerBase::loadTexture(Texture* texture, 
-        const Region& dirty, const GGLSurface& t) const
-{
-    if (texture->name == -1U) {
-        // uh?
-        return;
-    }
-
-    glBindTexture(GL_TEXTURE_2D, texture->name);
-
-    /*
-     * In OpenGL ES we can't specify a stride with glTexImage2D (however,
-     * GL_UNPACK_ALIGNMENT is a limited form of stride).
-     * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
-     * need to do something reasonable (here creating a bigger texture).
-     * 
-     * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
-     * 
-     * This situation doesn't happen often, but some h/w have a limitation
-     * for their framebuffer (eg: must be multiple of 8 pixels), and
-     * we need to take that into account when using these buffers as
-     * textures.
-     *
-     * This should never be a problem with POT textures
-     */
-    
-    int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
-    unpack = 1 << ((unpack > 3) ? 3 : unpack);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
-    
-    /*
-     * round to POT if needed 
-     */
-    if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
-        texture->NPOTAdjust = true;
-    }
-    
-    if (texture->NPOTAdjust) {
-        // find the smallest power-of-two that will accommodate our surface
-        texture->potWidth  = 1 << (31 - clz(t.width));
-        texture->potHeight = 1 << (31 - clz(t.height));
-        if (texture->potWidth  < t.width)  texture->potWidth  <<= 1;
-        if (texture->potHeight < t.height) texture->potHeight <<= 1;
-        texture->wScale = float(t.width)  / texture->potWidth;
-        texture->hScale = float(t.height) / texture->potHeight;
-    } else {
-        texture->potWidth  = t.width;
-        texture->potHeight = t.height;
-    }
-
-    Rect bounds(dirty.bounds());
-    GLvoid* data = 0;
-    if (texture->width != t.width || texture->height != t.height) {
-        texture->width  = t.width;
-        texture->height = t.height;
-
-        // texture size changed, we need to create a new one
-        bounds.set(Rect(t.width, t.height));
-        if (t.width  == texture->potWidth &&
-            t.height == texture->potHeight) {
-            // we can do it one pass
-            data = t.data;
-        }
-
-        if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
-            glTexImage2D(GL_TEXTURE_2D, 0,
-                    GL_RGB, texture->potWidth, texture->potHeight, 0,
-                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
-        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
-            glTexImage2D(GL_TEXTURE_2D, 0,
-                    GL_RGBA, texture->potWidth, texture->potHeight, 0,
-                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
-        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
-                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
-            glTexImage2D(GL_TEXTURE_2D, 0,
-                    GL_RGBA, texture->potWidth, texture->potHeight, 0,
-                    GL_RGBA, GL_UNSIGNED_BYTE, data);
-        } else if (isSupportedYuvFormat(t.format)) {
-            // just show the Y plane of YUV buffers
-            glTexImage2D(GL_TEXTURE_2D, 0,
-                    GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
-                    GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
-        } else {
-            // oops, we don't handle this format!
-            LOGE("layer %p, texture=%d, using format %d, which is not "
-                 "supported by the GL", this, texture->name, t.format);
-        }
-    }
-    if (!data) {
-        if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
-            glTexSubImage2D(GL_TEXTURE_2D, 0,
-                    0, bounds.top, t.width, bounds.height(),
-                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
-                    t.data + bounds.top*t.stride*2);
-        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
-            glTexSubImage2D(GL_TEXTURE_2D, 0,
-                    0, bounds.top, t.width, bounds.height(),
-                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
-                    t.data + bounds.top*t.stride*2);
-        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
-                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
-            glTexSubImage2D(GL_TEXTURE_2D, 0,
-                    0, bounds.top, t.width, bounds.height(),
-                    GL_RGBA, GL_UNSIGNED_BYTE,
-                    t.data + bounds.top*t.stride*4);
-        } else if (isSupportedYuvFormat(t.format)) {
-            // just show the Y plane of YUV buffers
-            glTexSubImage2D(GL_TEXTURE_2D, 0,
-                    0, bounds.top, t.width, bounds.height(),
-                    GL_LUMINANCE, GL_UNSIGNED_BYTE,
-                    t.data + bounds.top*t.stride);
-        }
-    }
-}
-
-status_t LayerBase::initializeEglImage(
-        const sp<GraphicBuffer>& buffer, Texture* texture)
-{
-    status_t err = NO_ERROR;
-
-    // we need to recreate the texture
-    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-
-    // free the previous image
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(dpy, texture->image);
-        texture->image = EGL_NO_IMAGE_KHR;
-    }
-
-    // construct an EGL_NATIVE_BUFFER_ANDROID
-    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
-
-    // create the new EGLImageKHR
-    const EGLint attrs[] = {
-            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
-            EGL_NONE,                   EGL_NONE
-    };
-    texture->image = eglCreateImageKHR(
-            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-            (EGLClientBuffer)clientBuf, attrs);
-
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        glBindTexture(GL_TEXTURE_2D, texture->name);
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
-                (GLeglImageOES)texture->image);
-        GLint error = glGetError();
-        if (UNLIKELY(error != GL_NO_ERROR)) {
-            LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) "
-                 "failed err=0x%04x",
-                 this, texture->image, error);
-            err = INVALID_OPERATION;
-        } else {
-            // Everything went okay!
-            texture->NPOTAdjust = false;
-            texture->dirty  = false;
-            texture->width  = clientBuf->width;
-            texture->height = clientBuf->height;
-        }
-    } else {
-        LOGE("layer=%p, eglCreateImageKHR() failed. err=0x%4x",
-                this, eglGetError());
-        err = INVALID_OPERATION;
-    }
-    return err;
-}
-
 void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
 {
     const Layer::State& s(drawingState());
@@ -696,12 +504,9 @@
 
 LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
         const sp<Client>& client, int32_t i)
-    : LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i),
+    : LayerBase(flinger, display), client(client), mIndex(i),
       mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
 {
-    lcblk = new SharedBufferServer(
-            client->ctrlblk, i, NUM_BUFFERS,
-            mIdentity);
 }
 
 void LayerBaseClient::onFirstRef()
@@ -718,7 +523,6 @@
     if (client != 0) {
         client->free(mIndex);
     }
-    delete lcblk;
 }
 
 ssize_t LayerBaseClient::serverIndex() const
@@ -748,14 +552,6 @@
             const_cast<LayerBaseClient *>(this));
 }
 
-// called with SurfaceFlinger::mStateLock as soon as the layer is entered
-// in the purgatory list
-void LayerBaseClient::onRemoved()
-{
-    // wake up the condition
-    lcblk->setStatus(NO_INIT);
-}
-
 void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const
 {
     LayerBase::dump(result, buffer, SIZE);
@@ -825,6 +621,11 @@
     return NULL; 
 }
 
+status_t LayerBaseClient::Surface::setBufferCount(int bufferCount)
+{
+    return INVALID_OPERATION;
+}
+
 status_t LayerBaseClient::Surface::registerBuffers(
         const ISurface::BufferHeap& buffers) 
 { 
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 219a53c..53b848f 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -46,6 +46,7 @@
 class GraphicBuffer;
 class GraphicPlane;
 class SurfaceFlinger;
+class Texture;
 
 // ---------------------------------------------------------------------------
 
@@ -221,35 +222,10 @@
     const GraphicPlane& graphicPlane(int dpy) const;
           GraphicPlane& graphicPlane(int dpy);
 
-          GLuint createTexture() const;
-    
-          struct Texture {
-              Texture() : name(-1U), width(0), height(0),
-                  image(EGL_NO_IMAGE_KHR), transform(0), 
-                  NPOTAdjust(false), dirty(true) { }
-              GLuint        name;
-              GLuint        width;
-              GLuint        height;
-              GLuint        potWidth;
-              GLuint        potHeight;
-              GLfloat       wScale;
-              GLfloat       hScale;
-              EGLImageKHR   image;
-              uint32_t      transform;
-              bool          NPOTAdjust;
-              bool          dirty;
-          };
-
           void clearWithOpenGL(const Region& clip, GLclampx r, GLclampx g,
                                GLclampx b, GLclampx alpha) const;
           void clearWithOpenGL(const Region& clip) const;
           void drawWithOpenGL(const Region& clip, const Texture& texture) const;
-          void loadTexture(Texture* texture, 
-                  const Region& dirty, const GGLSurface& t) const;
-          status_t initializeEglImage(
-                  const sp<GraphicBuffer>& buffer, Texture* texture);
-
-          bool isSupportedYuvFormat(int format) const;
           
                 sp<SurfaceFlinger> mFlinger;
                 uint32_t        mFlags;
@@ -294,10 +270,6 @@
 public:
     class Surface;
 
-    // lcblk is (almost) only accessed from the main SF thread, in the places
-    // where it's not, a reference to Client must be held
-    SharedBufferServer*     lcblk;
-
     LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, 
             const sp<Client>& client, int32_t i);
     virtual ~LayerBaseClient();
@@ -311,7 +283,6 @@
             sp<Surface> getSurface();
     virtual sp<Surface> createSurface() const;
     virtual ssize_t     serverIndex() const;
-    virtual void        onRemoved();
     virtual const char* getTypeId() const { return "LayerBaseClient"; }
 
     class Surface : public BnSurface 
@@ -331,6 +302,8 @@
 
     private:
         virtual sp<GraphicBuffer> requestBuffer(int index, int usage);
+        virtual status_t setBufferCount(int bufferCount);
+
         virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); 
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 0041a0f..dfcc80f 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -328,7 +328,7 @@
 LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
         const ISurface::BufferHeap& buffers)
     : Source(layer), mStatus(NO_ERROR), mBufferSize(0),
-      mUseEGLImageDirectly(true)
+      mTextureManager(layer.mFlags)
 {
     if (buffers.heap == NULL) {
         // this is allowed, but in this case, it is illegal to receive
@@ -460,35 +460,10 @@
     NativeBuffer src(ourBuffer->getBuffer());
     const Rect transformedBounds(mLayer.getTransformedBounds());
 
-    if (UNLIKELY(mTexture.name == -1LU)) {
-        mTexture.name = mLayer.createTexture();
-    }
-
 #if defined(EGL_ANDROID_image_native_buffer)
     if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
         err = INVALID_OPERATION;
         if (ourBuffer->supportsCopybit()) {
-
-            // there are constraints on buffers used by the GPU and these may not
-            // be honored here. We need to change the API so the buffers
-            // are allocated with gralloc. For now disable this code-path
-#if 0
-            // First, try to use the buffer as an EGLImage directly
-            if (mUseEGLImageDirectly) {
-                // NOTE: Assume the buffer is allocated with the proper USAGE flags
-
-                sp<GraphicBuffer> buffer = new  GraphicBuffer(
-                        src.img.w, src.img.h, src.img.format,
-                        GraphicBuffer::USAGE_HW_TEXTURE,
-                        src.img.w, src.img.handle, false);
-
-                err = mLayer.initializeEglImage(buffer, &mTexture);
-                if (err != NO_ERROR) {
-                    mUseEGLImageDirectly = false;
-                }
-            }
-#endif
-
             copybit_device_t* copybit = mLayer.mBlitEngine;
             if (copybit && err != NO_ERROR) {
                 // create our EGLImageKHR the first time
@@ -525,7 +500,7 @@
         t.format = src.img.format;
         t.data = (GGLubyte*)src.img.base;
         const Region dirty(Rect(t.width, t.height));
-        mLayer.loadTexture(&mTexture, dirty, t);
+        mTextureManager.loadTexture(&mTexture, dirty, t);
     }
 
     mTexture.transform = mBufferHeap.transform;
@@ -591,7 +566,8 @@
         dst.crop.r = w;
         dst.crop.b = h;
 
-        err = mLayer.initializeEglImage(buffer, &mTexture);
+        EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
+        err = mTextureManager.initEglImage(&mTexture, dpy, buffer);
     }
 
     return err;
@@ -607,7 +583,6 @@
     glDeleteTextures(1, &mTexture.name);
     Texture defaultTexture;
     mTexture = defaultTexture;
-    mTexture.name = mLayer.createTexture();
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 243cc43..869c74f 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include "LayerBase.h"
+#include "TextureManager.h"
 
 struct copybit_device_t;
 
@@ -139,9 +140,9 @@
         status_t                        mStatus;
         ISurface::BufferHeap            mBufferHeap;
         size_t                          mBufferSize;
-        mutable LayerBase::Texture      mTexture;
+        mutable Texture                 mTexture;
         mutable NativeBuffer            mTempBuffer;
-        mutable bool                    mUseEGLImageDirectly;
+        mutable TextureManager          mTextureManager;
     };
     
     class OverlaySource : public Source {
diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp
new file mode 100644
index 0000000..e5d5302
--- /dev/null
+++ b/libs/surfaceflinger/TextureManager.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <hardware/hardware.h>
+
+#include "clz.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "TextureManager.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+TextureManager::TextureManager(uint32_t flags)
+    : mFlags(flags)
+{
+}
+
+GLuint TextureManager::createTexture()
+{
+    GLuint textureName = -1;
+    glGenTextures(1, &textureName);
+    glBindTexture(GL_TEXTURE_2D, textureName);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    return textureName;
+}
+
+bool TextureManager::isSupportedYuvFormat(int format)
+{
+    switch (format) {
+        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+        case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+        case HAL_PIXEL_FORMAT_YCbCr_422_P:
+        case HAL_PIXEL_FORMAT_YCbCr_420_P:
+        case HAL_PIXEL_FORMAT_YCbCr_422_I:
+        case HAL_PIXEL_FORMAT_YCbCr_420_I:
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            return true;
+    }
+    return false;
+}
+
+status_t TextureManager::initEglImage(Texture* texture,
+        EGLDisplay dpy, const sp<GraphicBuffer>& buffer)
+{
+    status_t err = NO_ERROR;
+    if (!texture->dirty) return err;
+
+    // free the previous image
+    if (texture->image != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(dpy, texture->image);
+        texture->image = EGL_NO_IMAGE_KHR;
+    }
+
+    // construct an EGL_NATIVE_BUFFER_ANDROID
+    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+    // create the new EGLImageKHR
+    const EGLint attrs[] = {
+            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
+            EGL_NONE,                   EGL_NONE
+    };
+    texture->image = eglCreateImageKHR(
+            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+            (EGLClientBuffer)clientBuf, attrs);
+
+    if (texture->image != EGL_NO_IMAGE_KHR) {
+        if (texture->name == -1UL) {
+            texture->name = createTexture();
+            texture->width = 0;
+            texture->height = 0;
+        }
+        glBindTexture(GL_TEXTURE_2D, texture->name);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+                (GLeglImageOES)texture->image);
+        GLint error = glGetError();
+        if (error != GL_NO_ERROR) {
+            LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x",
+                    texture->image, error);
+            err = INVALID_OPERATION;
+        } else {
+            // Everything went okay!
+            texture->NPOTAdjust = false;
+            texture->dirty  = false;
+            texture->width  = clientBuf->width;
+            texture->height = clientBuf->height;
+        }
+    } else {
+        LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
+        err = INVALID_OPERATION;
+    }
+    return err;
+}
+
+status_t TextureManager::loadTexture(Texture* texture,
+        const Region& dirty, const GGLSurface& t)
+{
+    if (texture->name == -1UL) {
+        texture->name = createTexture();
+        texture->width = 0;
+        texture->height = 0;
+    }
+
+    glBindTexture(GL_TEXTURE_2D, texture->name);
+
+    /*
+     * In OpenGL ES we can't specify a stride with glTexImage2D (however,
+     * GL_UNPACK_ALIGNMENT is a limited form of stride).
+     * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
+     * need to do something reasonable (here creating a bigger texture).
+     *
+     * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
+     *
+     * This situation doesn't happen often, but some h/w have a limitation
+     * for their framebuffer (eg: must be multiple of 8 pixels), and
+     * we need to take that into account when using these buffers as
+     * textures.
+     *
+     * This should never be a problem with POT textures
+     */
+
+    int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
+    unpack = 1 << ((unpack > 3) ? 3 : unpack);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
+
+    /*
+     * round to POT if needed
+     */
+    if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
+        texture->NPOTAdjust = true;
+    }
+
+    if (texture->NPOTAdjust) {
+        // find the smallest power-of-two that will accommodate our surface
+        texture->potWidth  = 1 << (31 - clz(t.width));
+        texture->potHeight = 1 << (31 - clz(t.height));
+        if (texture->potWidth  < t.width)  texture->potWidth  <<= 1;
+        if (texture->potHeight < t.height) texture->potHeight <<= 1;
+        texture->wScale = float(t.width)  / texture->potWidth;
+        texture->hScale = float(t.height) / texture->potHeight;
+    } else {
+        texture->potWidth  = t.width;
+        texture->potHeight = t.height;
+    }
+
+    Rect bounds(dirty.bounds());
+    GLvoid* data = 0;
+    if (texture->width != t.width || texture->height != t.height) {
+        texture->width  = t.width;
+        texture->height = t.height;
+
+        // texture size changed, we need to create a new one
+        bounds.set(Rect(t.width, t.height));
+        if (t.width  == texture->potWidth &&
+            t.height == texture->potHeight) {
+            // we can do it one pass
+            data = t.data;
+        }
+
+        if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
+            glTexImage2D(GL_TEXTURE_2D, 0,
+                    GL_RGB, texture->potWidth, texture->potHeight, 0,
+                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
+        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
+            glTexImage2D(GL_TEXTURE_2D, 0,
+                    GL_RGBA, texture->potWidth, texture->potHeight, 0,
+                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
+        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
+                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
+            glTexImage2D(GL_TEXTURE_2D, 0,
+                    GL_RGBA, texture->potWidth, texture->potHeight, 0,
+                    GL_RGBA, GL_UNSIGNED_BYTE, data);
+        } else if (isSupportedYuvFormat(t.format)) {
+            // just show the Y plane of YUV buffers
+            glTexImage2D(GL_TEXTURE_2D, 0,
+                    GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
+                    GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+        } else {
+            // oops, we don't handle this format!
+            LOGE("texture=%d, using format %d, which is not "
+                 "supported by the GL", texture->name, t.format);
+        }
+    }
+    if (!data) {
+        if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
+            glTexSubImage2D(GL_TEXTURE_2D, 0,
+                    0, bounds.top, t.width, bounds.height(),
+                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
+                    t.data + bounds.top*t.stride*2);
+        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
+            glTexSubImage2D(GL_TEXTURE_2D, 0,
+                    0, bounds.top, t.width, bounds.height(),
+                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
+                    t.data + bounds.top*t.stride*2);
+        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
+                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
+            glTexSubImage2D(GL_TEXTURE_2D, 0,
+                    0, bounds.top, t.width, bounds.height(),
+                    GL_RGBA, GL_UNSIGNED_BYTE,
+                    t.data + bounds.top*t.stride*4);
+        } else if (isSupportedYuvFormat(t.format)) {
+            // just show the Y plane of YUV buffers
+            glTexSubImage2D(GL_TEXTURE_2D, 0,
+                    0, bounds.top, t.width, bounds.height(),
+                    GL_LUMINANCE, GL_UNSIGNED_BYTE,
+                    t.data + bounds.top*t.stride);
+        }
+    }
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/TextureManager.h b/libs/surfaceflinger/TextureManager.h
new file mode 100644
index 0000000..90cb62b
--- /dev/null
+++ b/libs/surfaceflinger/TextureManager.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_TEXTURE_MANAGER_H
+#define ANDROID_TEXTURE_MANAGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+
+#include <ui/Region.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class GraphicBuffer;
+
+// ---------------------------------------------------------------------------
+
+struct Texture {
+    Texture() : name(-1U), width(0), height(0),
+        image(EGL_NO_IMAGE_KHR), transform(0),
+        NPOTAdjust(false), dirty(true) { }
+    GLuint        name;
+    GLuint        width;
+    GLuint        height;
+    GLuint        potWidth;
+    GLuint        potHeight;
+    GLfloat       wScale;
+    GLfloat       hScale;
+    EGLImageKHR   image;
+    uint32_t      transform;
+    bool          NPOTAdjust;
+    bool          dirty;
+};
+
+// ---------------------------------------------------------------------------
+
+class TextureManager {
+    uint32_t mFlags;
+    GLuint createTexture();
+    static bool isSupportedYuvFormat(int format);
+public:
+
+    TextureManager(uint32_t flags);
+
+    // load bitmap data into the active buffer
+    status_t loadTexture(Texture* texture,
+            const Region& dirty, const GGLSurface& t);
+
+    // make active buffer an EGLImage if needed
+    status_t initEglImage(Texture* texture,
+            EGLDisplay dpy, const sp<GraphicBuffer>& buffer);
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_TEXTURE_MANAGER_H
diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp
index bb86199..c5d0c0e 100644
--- a/libs/surfaceflinger_client/ISurface.cpp
+++ b/libs/surfaceflinger_client/ISurface.cpp
@@ -83,6 +83,16 @@
         return buffer;
     }
 
+    virtual status_t setBufferCount(int bufferCount)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+        data.writeInt32(bufferCount);
+        remote()->transact(SET_BUFFER_COUNT, data, &reply);
+        status_t err = reply.readInt32();
+        return err;
+    }
+
     virtual status_t registerBuffers(const BufferHeap& buffers)
     {
         Parcel data, reply;
@@ -146,6 +156,13 @@
                 return BAD_VALUE;
             return reply->write(*buffer);
         }
+        case SET_BUFFER_COUNT: {
+            CHECK_INTERFACE(ISurface, data, reply);
+            int bufferCount = data.readInt32();
+            status_t err = setBufferCount(bufferCount);
+            reply->writeInt32(err);
+            return NO_ERROR;
+        }
         case REGISTER_BUFFERS: {
             CHECK_INTERFACE(ISurface, data, reply);
             BufferHeap buffer;
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index c42cd53..4a98026 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -305,7 +305,6 @@
     : UpdateBase(sbb), numBuffers(numBuffers) {
 }
 ssize_t SharedBufferServer::RetireUpdate::operator()() {
-    // head is only written in this function, which is single-thread.
     int32_t head = stack.head;
     if (uint32_t(head) >= NUM_BUFFER_MAX)
         return BAD_VALUE;
@@ -322,16 +321,14 @@
         }
     } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
     
-    // update the head pointer
-    head = ((head+1 >= numBuffers) ? 0 : head+1);
-
     // lock the buffer before advancing head, which automatically unlocks
     // the buffer we preventively locked upon entering this function
+    head = (head + 1) % numBuffers;
     android_atomic_write(stack.index[head], &stack.inUse);
 
-    // advance head
+    // head is only modified here, so we don't need to use cmpxchg
     android_atomic_write(head, &stack.head);
-    
+
     // now that head has moved, we can increment the number of available buffers
     android_atomic_inc(&stack.available);
     return head;
@@ -450,6 +447,14 @@
     return stack.setDirtyRegion(buf, reg);
 }
 
+status_t SharedBufferClient::setBufferCount(int bufferCount)
+{
+    if (uint32_t(bufferCount) >= NUM_BUFFER_MAX)
+        return BAD_VALUE;
+    mNumBuffers = bufferCount;
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
@@ -463,6 +468,7 @@
     mSharedStack->reallocMask = 0;
     memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers));
     for (int i=0 ; i<num ; i++) {
+        mBufferList.add(i);
         mSharedStack->index[i] = i;
     }
 }
@@ -513,6 +519,7 @@
 
 status_t SharedBufferServer::assertReallocate(int buf)
 {
+    // TODO: need to validate "buf"
     ReallocateCondition condition(this, buf);
     status_t err = waitForCondition(condition);
     return err;
@@ -524,12 +531,85 @@
     return stack.getDirtyRegion(buf);
 }
 
+
+/*
+ *
+ * NOTE: this is not thread-safe on the server-side, meaning
+ * 'head' cannot move during this operation. The client-side
+ * can safely operate an usual.
+ *
+ */
+status_t SharedBufferServer::resize(int newNumBuffers)
+{
+    if (uint32_t(newNumBuffers) >= NUM_BUFFER_MAX)
+        return BAD_VALUE;
+
+    // for now we're not supporting shrinking
+    const int numBuffers = mNumBuffers;
+    if (newNumBuffers < numBuffers)
+        return BAD_VALUE;
+
+    SharedBufferStack& stack( *mSharedStack );
+    const int extra = newNumBuffers - numBuffers;
+
+    // read the head, make sure it's valid
+    int32_t head = stack.head;
+    if (uint32_t(head) >= NUM_BUFFER_MAX)
+        return BAD_VALUE;
+
+    int base = numBuffers;
+    int32_t avail = stack.available;
+    int tail = head - avail + 1;
+    if (tail >= 0) {
+        int8_t* const index = const_cast<int8_t*>(stack.index);
+        const int nb = numBuffers - head;
+        memmove(&index[head + extra], &index[head], nb);
+        base = head;
+        // move head 'extra' ahead, this doesn't impact stack.index[head];
+        stack.head = head + extra;
+    }
+    stack.available += extra;
+
+    // fill the new free space with unused buffers
+    BufferList::const_iterator curr(mBufferList.free_begin());
+    for (int i=0 ; i<extra ; i++) {
+        stack.index[base+i] = *curr++;
+        mBufferList.add(stack.index[base+i]);
+    }
+
+    mNumBuffers = newNumBuffers;
+    return NO_ERROR;
+}
+
 SharedBufferStack::Statistics SharedBufferServer::getStats() const
 {
     SharedBufferStack& stack( *mSharedStack );
     return stack.stats;
 }
 
+// ---------------------------------------------------------------------------
+status_t SharedBufferServer::BufferList::add(int value)
+{
+    if (uint32_t(value) >= mCapacity)
+        return BAD_VALUE;
+    uint32_t mask = 1<<(31-value);
+    if (mList & mask)
+        return ALREADY_EXISTS;
+    mList |= mask;
+    return NO_ERROR;
+}
+
+status_t SharedBufferServer::BufferList::remove(int value)
+{
+    if (uint32_t(value) >= mCapacity)
+        return BAD_VALUE;
+    uint32_t mask = 1<<(31-value);
+    if (!(mList & mask))
+        return NAME_NOT_FOUND;
+    mList &= ~mask;
+    return NO_ERROR;
+}
+
 
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index eee4dae..afbeafb 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -673,6 +673,27 @@
     return NO_ERROR;
 }
 
+int Surface::setBufferCount(int bufferCount)
+{
+    sp<ISurface> s(mSurface);
+    if (s == 0) return NO_INIT;
+
+    // FIXME: this needs to be synchronized dequeue/queue
+
+    status_t err = s->setBufferCount(bufferCount);
+    LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
+            bufferCount, strerror(-err));
+    if (err == NO_ERROR) {
+        err = mSharedBufferClient->getStatus();
+        LOGE_IF(err,  "Surface (identity=%d) state = %d", mIdentity, err);
+        if (!err) {
+            // update our local copy of the buffer count
+            mSharedBufferClient->setBufferCount(bufferCount);
+        }
+    }
+    return err;
+}
+
 
 // ----------------------------------------------------------------------------
 
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 5a05e6a..60a0d82 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -824,7 +824,7 @@
 
     // TODO: look for previously-created shared memory slice?
     int method;
-    long uncompressedLen;
+    size_t uncompressedLen;
 
     //printf("USING Zip '%s'\n", pEntry->getFileName());
 
diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp
index 45f6c8b..16b219c 100644
--- a/libs/utils/ZipFileCRO.cpp
+++ b/libs/utils/ZipFileCRO.cpp
@@ -39,8 +39,8 @@
 }
 
 bool ZipFileCRO_getEntryInfo(ZipFileCRO zipToken, ZipEntryRO entryToken,
-        int* pMethod, long* pUncompLen,
-        long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) {
+        int* pMethod, size_t* pUncompLen,
+        size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) {
     ZipFileRO* zip = (ZipFileRO*)zipToken;
     ZipEntryRO entry = (ZipEntryRO)entryToken;
     return zip->getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset,
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index 6c701dd..28dc512 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -29,6 +29,22 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <assert.h>
+#include <unistd.h>
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
 
 using namespace android;
 
@@ -38,6 +54,7 @@
 #define kEOCDSignature      0x06054b50
 #define kEOCDLen            22
 #define kEOCDNumEntries     8               // offset to #of entries in file
+#define kEOCDSize           12              // size of the central directory
 #define kEOCDFileOffset     16              // offset to central directory
 
 #define kMaxCommentLen      65535           // longest possible in ushort
@@ -90,9 +107,8 @@
 status_t ZipFileRO::open(const char* zipFileName)
 {
     int fd = -1;
-    off_t length;
 
-    assert(mFileMap == NULL);
+    assert(mDirectoryMap == NULL);
 
     /*
      * Open and map the specified file.
@@ -103,172 +119,240 @@
         return NAME_NOT_FOUND;
     }
 
-    length = lseek(fd, 0, SEEK_END);
-    if (length < 0) {
+    mFileLength = lseek(fd, 0, SEEK_END);
+    if (mFileLength < kEOCDLen) {
         close(fd);
         return UNKNOWN_ERROR;
     }
 
-    mFileMap = new FileMap();
-    if (mFileMap == NULL) {
-        close(fd);
-        return NO_MEMORY;
+    if (mFileName != NULL) {
+        free(mFileName);
     }
-    if (!mFileMap->create(zipFileName, fd, 0, length, true)) {
-        LOGW("Unable to map '%s': %s\n", zipFileName, strerror(errno));
-        close(fd);
-        return UNKNOWN_ERROR;
-    }
+    mFileName = strdup(zipFileName);
 
     mFd = fd;
 
     /*
-     * Got it mapped, verify it and create data structures for fast access.
+     * Find the Central Directory and store its size and number of entries.
+     */
+    if (!mapCentralDirectory()) {
+        goto bail;
+    }
+
+    /*
+     * Verify Central Directory and create data structures for fast access.
      */
     if (!parseZipArchive()) {
-        mFileMap->release();
-        mFileMap = NULL;
-        return UNKNOWN_ERROR;
+        goto bail;
     }
 
     return OK;
+
+bail:
+    free(mFileName);
+    mFileName = NULL;
+    close(fd);
+    return UNKNOWN_ERROR;
 }
 
 /*
  * Parse the Zip archive, verifying its contents and initializing internal
  * data structures.
  */
+bool ZipFileRO::mapCentralDirectory(void)
+{
+    size_t readAmount = kMaxEOCDSearch;
+    if (readAmount > (size_t) mFileLength)
+        readAmount = mFileLength;
+
+    unsigned char* scanBuf = (unsigned char*) malloc(readAmount);
+    if (scanBuf == NULL) {
+        LOGW("couldn't allocate scanBuf: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    /*
+     * Make sure this is a Zip archive.
+     */
+    if (lseek(mFd, 0, SEEK_SET) != 0) {
+        LOGW("seek to start failed: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    ssize_t actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, sizeof(int32_t)));
+    if (actual != (ssize_t) sizeof(int32_t)) {
+        LOGI("couldn't read first signature from zip archive: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    {
+        unsigned int header = get4LE(scanBuf);
+        if (header == kEOCDSignature) {
+            LOGI("Found Zip archive, but it looks empty\n");
+            free(scanBuf);
+            return false;
+        } else if (header != kLFHSignature) {
+            LOGV("Not a Zip archive (found 0x%08x)\n", val);
+            free(scanBuf);
+            return false;
+        }
+    }
+
+    /*
+     * Perform the traditional EOCD snipe hunt.
+     *
+     * We're searching for the End of Central Directory magic number,
+     * which appears at the start of the EOCD block.  It's followed by
+     * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
+     * need to read the last part of the file into a buffer, dig through
+     * it to find the magic number, parse some values out, and use those
+     * to determine the extent of the CD.
+     *
+     * We start by pulling in the last part of the file.
+     */
+    off_t searchStart = mFileLength - readAmount;
+
+    if (lseek(mFd, searchStart, SEEK_SET) != searchStart) {
+        LOGW("seek %ld failed: %s\n",  (long) searchStart, strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+    actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, readAmount));
+    if (actual != (ssize_t) readAmount) {
+        LOGW("Zip: read %zd failed: %s\n", readAmount, strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    /*
+     * Scan backward for the EOCD magic.  In an archive without a trailing
+     * comment, we'll find it on the first try.  (We may want to consider
+     * doing an initial minimal read; if we don't find it, retry with a
+     * second read as above.)
+     */
+    int i;
+    for (i = readAmount - kEOCDLen; i >= 0; i--) {
+        if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
+            LOGV("+++ Found EOCD at buf+%d\n", i);
+            break;
+        }
+    }
+    if (i < 0) {
+        LOGD("Zip: EOCD not found, %s is not zip\n", mFileName);
+        free(scanBuf);
+        return false;
+    }
+
+    off_t eocdOffset = searchStart + i;
+    const unsigned char* eocdPtr = scanBuf + i;
+
+    assert(eocdOffset < mFileLength);
+
+    /*
+     * Grab the CD offset and size, and the number of entries in the
+     * archive.  Verify that they look reasonable.
+     */
+    unsigned int numEntries = get2LE(eocdPtr + kEOCDNumEntries);
+    unsigned int dirSize = get4LE(eocdPtr + kEOCDSize);
+    unsigned int dirOffset = get4LE(eocdPtr + kEOCDFileOffset);
+
+    if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) {
+        LOGW("bad offsets (dir %ld, size %u, eocd %ld)\n",
+            (long) dirOffset, dirSize, (long) eocdOffset);
+        free(scanBuf);
+        return false;
+    }
+    if (numEntries == 0) {
+        LOGW("empty archive?\n");
+        free(scanBuf);
+        return false;
+    }
+
+    LOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n",
+        numEntries, dirSize, dirOffset);
+
+    mDirectoryMap = new FileMap();
+    if (mDirectoryMap == NULL) {
+        LOGW("Unable to create directory map: %s", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    if (!mDirectoryMap->create(mFileName, mFd, dirOffset, dirSize, true)) {
+        LOGW("Unable to map '%s' (%zd to %zd): %s\n", mFileName,
+                dirOffset, dirOffset + dirSize, strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+    mNumEntries = numEntries;
+    mDirectoryOffset = dirOffset;
+
+    return true;
+}
+
 bool ZipFileRO::parseZipArchive(void)
 {
-#define CHECK_OFFSET(_off) {                                                \
-        if ((unsigned int) (_off) >= maxOffset) {                           \
-            LOGE("ERROR: bad offset %u (max %d): %s\n",                     \
-                (unsigned int) (_off), maxOffset, #_off);                   \
-            goto bail;                                                      \
-        }                                                                   \
-    }
-    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
-    const unsigned char* ptr;
-    size_t length = mFileMap->getDataLength();
     bool result = false;
-    unsigned int i, numEntries, cdOffset;
-    unsigned int val;
-
-    /*
-     * The first 4 bytes of the file will either be the local header
-     * signature for the first file (kLFHSignature) or, if the archive doesn't
-     * have any files in it, the end-of-central-directory signature
-     * (kEOCDSignature).
-     */
-    val = get4LE(basePtr);
-    if (val == kEOCDSignature) {
-        LOGI("Found Zip archive, but it looks empty\n");
-        goto bail;
-    } else if (val != kLFHSignature) {
-        LOGV("Not a Zip archive (found 0x%08x)\n", val);
-        goto bail;
-    }
-
-    /*
-     * Find the EOCD.  We'll find it immediately unless they have a file
-     * comment.
-     */
-    ptr = basePtr + length - kEOCDLen;
-
-    while (ptr >= basePtr) {
-        if (*ptr == (kEOCDSignature & 0xff) && get4LE(ptr) == kEOCDSignature)
-            break;
-        ptr--;
-    }
-    if (ptr < basePtr) {
-        LOGI("Could not find end-of-central-directory in Zip\n");
-        goto bail;
-    }
-
-    /*
-     * There are two interesting items in the EOCD block: the number of
-     * entries in the file, and the file offset of the start of the
-     * central directory.
-     *
-     * (There's actually a count of the #of entries in this file, and for
-     * all files which comprise a spanned archive, but for our purposes
-     * we're only interested in the current file.  Besides, we expect the
-     * two to be equivalent for our stuff.)
-     */
-    numEntries = get2LE(ptr + kEOCDNumEntries);
-    cdOffset = get4LE(ptr + kEOCDFileOffset);
-
-    /* valid offsets are [0,EOCD] */
-    unsigned int maxOffset;
-    maxOffset = (ptr - basePtr) +1;
-
-    LOGV("+++ numEntries=%d cdOffset=%d\n", numEntries, cdOffset);
-    if (numEntries == 0 || cdOffset >= length) {
-        LOGW("Invalid entries=%d offset=%d (len=%zd)\n",
-            numEntries, cdOffset, length);
-        goto bail;
-    }
+    const unsigned char* cdPtr = (const unsigned char*) mDirectoryMap->getDataPtr();
+    size_t cdLength = mDirectoryMap->getDataLength();
+    int numEntries = mNumEntries;
 
     /*
      * Create hash table.  We have a minimum 75% load factor, possibly as
      * low as 50% after we round off to a power of 2.
      */
-    mNumEntries = numEntries;
-    mHashTableSize = roundUpPower2(1 + ((numEntries * 4) / 3));
-    mHashTable = (HashEntry*) calloc(1, sizeof(HashEntry) * mHashTableSize);
+    mHashTableSize = roundUpPower2(1 + (numEntries * 4) / 3);
+    mHashTable = (HashEntry*) calloc(mHashTableSize, sizeof(HashEntry));
 
     /*
      * Walk through the central directory, adding entries to the hash
      * table.
      */
-    ptr = basePtr + cdOffset;
-    for (i = 0; i < numEntries; i++) {
-        unsigned int fileNameLen, extraLen, commentLen, localHdrOffset;
-        const unsigned char* localHdr;
-        unsigned int hash;
-
+    const unsigned char* ptr = cdPtr;
+    for (int i = 0; i < numEntries; i++) {
         if (get4LE(ptr) != kCDESignature) {
             LOGW("Missed a central dir sig (at %d)\n", i);
             goto bail;
         }
-        if (ptr + kCDELen > basePtr + length) {
+        if (ptr + kCDELen > cdPtr + cdLength) {
             LOGW("Ran off the end (at %d)\n", i);
             goto bail;
         }
 
-        localHdrOffset = get4LE(ptr + kCDELocalOffset);
-        CHECK_OFFSET(localHdrOffset);
+        long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
+        if (localHdrOffset >= mDirectoryOffset) {
+            LOGW("bad LFH offset %ld at entry %d\n", localHdrOffset, i);
+            goto bail;
+        }
+
+        unsigned int fileNameLen, extraLen, commentLen, hash;
+
         fileNameLen = get2LE(ptr + kCDENameLen);
         extraLen = get2LE(ptr + kCDEExtraLen);
         commentLen = get2LE(ptr + kCDECommentLen);
 
-        //LOGV("+++ %d: localHdr=%d fnl=%d el=%d cl=%d\n",
-        //    i, localHdrOffset, fileNameLen, extraLen, commentLen);
-        //LOGV(" '%.*s'\n", fileNameLen, ptr + kCDELen);
-
         /* add the CDE filename to the hash table */
         hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
         addToHash((const char*)ptr + kCDELen, fileNameLen, hash);
 
-        localHdr = basePtr + localHdrOffset;
-        if (get4LE(localHdr) != kLFHSignature) {
-            LOGW("Bad offset to local header: %d (at %d)\n",
-                localHdrOffset, i);
+        ptr += kCDELen + fileNameLen + extraLen + commentLen;
+        if ((size_t)(ptr - cdPtr) > cdLength) {
+            LOGW("bad CD advance (%d vs %zd) at entry %d\n",
+                (int) (ptr - cdPtr), cdLength, i);
             goto bail;
         }
-
-        ptr += kCDELen + fileNameLen + extraLen + commentLen;
-        CHECK_OFFSET(ptr - basePtr);
     }
-
+    LOGV("+++ zip good scan %d entries\n", numEntries);
     result = true;
 
 bail:
     return result;
-#undef CHECK_OFFSET
 }
 
-
 /*
  * Simple string hash function for non-null-terminated strings.
  */
@@ -315,7 +399,7 @@
             memcmp(mHashTable[ent].name, fileName, nameLen) == 0)
         {
             /* match */
-            return (ZipEntryRO) (ent + kZipEntryAdj);
+            return (ZipEntryRO)(long)(ent + kZipEntryAdj);
         }
 
         ent = (ent + 1) & (mHashTableSize-1);
@@ -354,20 +438,24 @@
  * Returns "false" if the offsets to the fields or the contents of the fields
  * appear to be bogus.
  */
-bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen,
-    long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const
+bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
+    size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const
 {
-    int ent = entryToIndex(entry);
+    bool ret = false;
+
+    const int ent = entryToIndex(entry);
     if (ent < 0)
         return false;
 
+    HashEntry hashEntry = mHashTable[ent];
+
     /*
      * Recover the start of the central directory entry from the filename
-     * pointer.
+     * pointer.  The filename is the first entry past the fixed-size data,
+     * so we can just subtract back from that.
      */
-    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
-    const unsigned char* ptr = (const unsigned char*) mHashTable[ent].name;
-    size_t zipLength = mFileMap->getDataLength();
+    const unsigned char* ptr = (const unsigned char*) hashEntry.name;
+    off_t cdOffset = mDirectoryOffset;
 
     ptr -= kCDELen;
 
@@ -380,48 +468,78 @@
     if (pCrc32 != NULL)
         *pCrc32 = get4LE(ptr + kCDECRC);
 
+    size_t compLen = get4LE(ptr + kCDECompLen);
+    if (pCompLen != NULL)
+        *pCompLen = compLen;
+    size_t uncompLen = get4LE(ptr + kCDEUncompLen);
+    if (pUncompLen != NULL)
+        *pUncompLen = uncompLen;
+
     /*
-     * We need to make sure that the lengths are not so large that somebody
-     * trying to map the compressed or uncompressed data runs off the end
-     * of the mapped region.
+     * If requested, determine the offset of the start of the data.  All we
+     * have is the offset to the Local File Header, which is variable size,
+     * so we have to read the contents of the struct to figure out where
+     * the actual data starts.
+     *
+     * We also need to make sure that the lengths are not so large that
+     * somebody trying to map the compressed or uncompressed data runs
+     * off the end of the mapped region.
+     *
+     * Note we don't verify compLen/uncompLen if they don't request the
+     * dataOffset, because dataOffset is expensive to determine.  However,
+     * if they don't have the file offset, they're not likely to be doing
+     * anything with the contents.
      */
-    unsigned long localHdrOffset = get4LE(ptr + kCDELocalOffset);
-    if (localHdrOffset + kLFHLen >= zipLength) {
-        LOGE("ERROR: bad local hdr offset in zip\n");
-        return false;
-    }
-    const unsigned char* localHdr = basePtr + localHdrOffset;
-    off_t dataOffset = localHdrOffset + kLFHLen
-        + get2LE(localHdr + kLFHNameLen) + get2LE(localHdr + kLFHExtraLen);
-    if ((unsigned long) dataOffset >= zipLength) {
-        LOGE("ERROR: bad data offset in zip\n");
-        return false;
-    }
-
-    if (pCompLen != NULL) {
-        *pCompLen = get4LE(ptr + kCDECompLen);
-        if (*pCompLen < 0 || (size_t)(dataOffset + *pCompLen) >= zipLength) {
-            LOGE("ERROR: bad compressed length in zip\n");
-            return false;
-        }
-    }
-    if (pUncompLen != NULL) {
-        *pUncompLen = get4LE(ptr + kCDEUncompLen);
-        if (*pUncompLen < 0) {
-            LOGE("ERROR: negative uncompressed length in zip\n");
-            return false;
-        }
-        if (method == kCompressStored &&
-            (size_t)(dataOffset + *pUncompLen) >= zipLength)
-        {
-            LOGE("ERROR: bad uncompressed length in zip\n");
-            return false;
-        }
-    }
-
     if (pOffset != NULL) {
+        long localHdrOffset = get4LE(ptr + kCDELocalOffset);
+        if (localHdrOffset + kLFHLen >= cdOffset) {
+            LOGE("ERROR: bad local hdr offset in zip\n");
+            return false;
+        }
+
+        unsigned char lfhBuf[kLFHLen];
+        if (lseek(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
+            LOGW("failed seeking to lfh at offset %ld\n", localHdrOffset);
+            return false;
+        }
+        ssize_t actual =
+            TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf)));
+        if (actual != sizeof(lfhBuf)) {
+            LOGW("failed reading lfh from offset %ld\n", localHdrOffset);
+            return false;
+        }
+
+        if (get4LE(lfhBuf) != kLFHSignature) {
+            LOGW("didn't find signature at start of lfh, offset=%ld\n",
+                localHdrOffset);
+            return false;
+        }
+
+        off_t dataOffset = localHdrOffset + kLFHLen
+            + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
+        if (dataOffset >= cdOffset) {
+            LOGW("bad data offset %ld in zip\n", (long) dataOffset);
+            return false;
+        }
+
+        /* check lengths */
+        if ((off_t)(dataOffset + compLen) > cdOffset) {
+            LOGW("bad compressed length in zip (%ld + %zd > %ld)\n",
+                (long) dataOffset, compLen, (long) cdOffset);
+            return false;
+        }
+
+        if (method == kCompressStored &&
+            (off_t)(dataOffset + uncompLen) > cdOffset)
+        {
+            LOGE("ERROR: bad uncompressed length in zip (%ld + %zd > %ld)\n",
+                (long) dataOffset, uncompLen, (long) cdOffset);
+            return false;
+        }
+
         *pOffset = dataOffset;
     }
+
     return true;
 }
 
@@ -457,14 +575,14 @@
      */
 
     FileMap* newMap;
-    long compLen;
+    size_t compLen;
     off_t offset;
 
     if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL))
         return NULL;
 
     newMap = new FileMap();
-    if (!newMap->create(mFileMap->getFileName(), mFd, offset, compLen, true)) {
+    if (!newMap->create(mFileName, mFd, offset, compLen, true)) {
         newMap->release();
         return NULL;
     }
@@ -480,19 +598,26 @@
  */
 bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const
 {
-    const int kSequentialMin = 32768;
+    const size_t kSequentialMin = 32768;
     bool result = false;
     int ent = entryToIndex(entry);
     if (ent < 0)
         return -1;
 
-    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
     int method;
-    long uncompLen, compLen;
+    size_t uncompLen, compLen;
     off_t offset;
+    const unsigned char* ptr;
 
     getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
 
+    FileMap* file = createEntryFileMap(entry);
+    if (file == NULL) {
+        goto bail;
+    }
+
+    ptr = (const unsigned char*) file->getDataPtr();
+
     /*
      * Experiment with madvise hint.  When we want to uncompress a file,
      * we pull some stuff out of the central dir entry and then hit a
@@ -507,17 +632,17 @@
      * pair of system calls are negated by a reduction in page faults.
      */
     if (compLen > kSequentialMin)
-        mFileMap->advise(FileMap::SEQUENTIAL);
+        file->advise(FileMap::SEQUENTIAL);
 
     if (method == kCompressStored) {
-        memcpy(buffer, basePtr + offset, uncompLen);
+        memcpy(buffer, ptr, uncompLen);
     } else {
-        if (!inflateBuffer(buffer, basePtr + offset, uncompLen, compLen))
+        if (!inflateBuffer(buffer, ptr, uncompLen, compLen))
             goto bail;
     }
 
     if (compLen > kSequentialMin)
-        mFileMap->advise(FileMap::NORMAL);
+        file->advise(FileMap::NORMAL);
 
     result = true;
 
@@ -537,29 +662,34 @@
     if (ent < 0)
         return -1;
 
-    const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr();
     int method;
-    long uncompLen, compLen;
+    size_t uncompLen, compLen;
     off_t offset;
+    const unsigned char* ptr;
 
     getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
 
-    if (method == kCompressStored) {
-        ssize_t actual;
+    const FileMap* file = createEntryFileMap(entry);
+    if (file == NULL) {
+        goto bail;
+    }
 
-        actual = write(fd, basePtr + offset, uncompLen);
+    ptr = (const unsigned char*) file->getDataPtr();
+
+    if (method == kCompressStored) {
+        ssize_t actual = write(fd, ptr, uncompLen);
         if (actual < 0) {
             LOGE("Write failed: %s\n", strerror(errno));
             goto bail;
-        } else if (actual != uncompLen) {
-            LOGE("Partial write during uncompress (%d of %ld)\n",
-                (int)actual, uncompLen);
+        } else if ((size_t) actual != uncompLen) {
+            LOGE("Partial write during uncompress (%zd of %zd)\n",
+                actual, uncompLen);
             goto bail;
         } else {
             LOGI("+++ successful write\n");
         }
     } else {
-        if (!inflateBuffer(fd, basePtr+offset, uncompLen, compLen))
+        if (!inflateBuffer(fd, ptr, uncompLen, compLen))
             goto bail;
     }
 
@@ -573,7 +703,7 @@
  * Uncompress "deflate" data from one buffer to another.
  */
 /*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf,
-    long uncompLen, long compLen)
+    size_t uncompLen, size_t compLen)
 {
     bool result = false;
     z_stream zstream;
@@ -582,7 +712,7 @@
     /*
      * Initialize the zlib stream struct.
      */
-	memset(&zstream, 0, sizeof(zstream));
+    memset(&zstream, 0, sizeof(zstream));
     zstream.zalloc = Z_NULL;
     zstream.zfree = Z_NULL;
     zstream.opaque = Z_NULL;
@@ -592,10 +722,10 @@
     zstream.avail_out = uncompLen;
     zstream.data_type = Z_UNKNOWN;
 
-	/*
-	 * Use the undocumented "negative window bits" feature to tell zlib
-	 * that there's no zlib header waiting for it.
-	 */
+    /*
+     * Use the undocumented "negative window bits" feature to tell zlib
+     * that there's no zlib header waiting for it.
+     */
     zerr = inflateInit2(&zstream, -MAX_WBITS);
     if (zerr != Z_OK) {
         if (zerr == Z_VERSION_ERROR) {
@@ -619,8 +749,8 @@
     }
 
     /* paranoia */
-    if ((long) zstream.total_out != uncompLen) {
-        LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+    if (zstream.total_out != uncompLen) {
+        LOGW("Size mismatch on inflated file (%ld vs %zd)\n",
             zstream.total_out, uncompLen);
         goto z_bail;
     }
@@ -638,10 +768,10 @@
  * Uncompress "deflate" data from one buffer to an open file descriptor.
  */
 /*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf,
-    long uncompLen, long compLen)
+    size_t uncompLen, size_t compLen)
 {
     bool result = false;
-    const int kWriteBufSize = 32768;
+    const size_t kWriteBufSize = 32768;
     unsigned char writeBuf[kWriteBufSize];
     z_stream zstream;
     int zerr;
@@ -649,7 +779,7 @@
     /*
      * Initialize the zlib stream struct.
      */
-	memset(&zstream, 0, sizeof(zstream));
+    memset(&zstream, 0, sizeof(zstream));
     zstream.zalloc = Z_NULL;
     zstream.zfree = Z_NULL;
     zstream.opaque = Z_NULL;
@@ -659,10 +789,10 @@
     zstream.avail_out = sizeof(writeBuf);
     zstream.data_type = Z_UNKNOWN;
 
-	/*
-	 * Use the undocumented "negative window bits" feature to tell zlib
-	 * that there's no zlib header waiting for it.
-	 */
+    /*
+     * Use the undocumented "negative window bits" feature to tell zlib
+     * that there's no zlib header waiting for it.
+     */
     zerr = inflateInit2(&zstream, -MAX_WBITS);
     if (zerr != Z_OK) {
         if (zerr == Z_VERSION_ERROR) {
@@ -708,8 +838,8 @@
     assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
 
     /* paranoia */
-    if ((long) zstream.total_out != uncompLen) {
-        LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
+    if (zstream.total_out != uncompLen) {
+        LOGW("Size mismatch on inflated file (%ld vs %zd)\n",
             zstream.total_out, uncompLen);
         goto z_bail;
     }
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 6cb146c..8abd649 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -37,6 +37,10 @@
 	LOCAL_CFLAGS += -fstrict-aliasing
 endif
 
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
+endif
+
 ifneq ($(TARGET_SIMULATOR),true)
     # we need to access the private Bionic header <bionic_tls.h>
     # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 9407bd5..d67612e 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -1515,7 +1515,7 @@
         ogles_error(c, GL_INVALID_VALUE);
         return;
     }
-    if (x<0 || x<0) {
+    if (x<0 || y<0) {
         ogles_error(c, GL_INVALID_VALUE);
         return;
     }