Merge "HWC 1.1: hook up hotplug event, use new display config queries" into jb-mr1-dev
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 85d8fb6..0a95bb3 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -92,13 +92,11 @@
     };
 
 
-    // BufferQueue manages a pool of gralloc memory slots to be used
-    // by producers and consumers.
-    // allowSynchronousMode specifies whether or not synchronous mode can be
-    // enabled.
-    // bufferCount sets the minimum number of undequeued buffers for this queue
+    // BufferQueue manages a pool of gralloc memory slots to be used by
+    // producers and consumers. allowSynchronousMode specifies whether or not
+    // synchronous mode can be enabled by the producer. allocator is used to
+    // allocate all the needed gralloc buffers.
     BufferQueue(bool allowSynchronousMode = true,
-            int bufferCount = MIN_UNDEQUEUED_BUFFERS,
             const sp<IGraphicBufferAlloc>& allocator = NULL);
     virtual ~BufferQueue();
 
@@ -252,10 +250,15 @@
     // requestBuffers when a with and height of zero is requested.
     status_t setDefaultBufferSize(uint32_t w, uint32_t h);
 
-    // setBufferCountServer set the buffer count. If the client has requested
+    // setDefaultBufferCount set the buffer count. If the client has requested
     // a buffer count using setBufferCount, the server-buffer count will
     // take effect once the client sets the count back to zero.
-    status_t setBufferCountServer(int bufferCount);
+    status_t setDefaultMaxBufferCount(int bufferCount);
+
+    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
+    // be acquired by the consumer at one time.  This call will fail if a
+    // producer is connected to the BufferQueue.
+    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
 
     // isSynchronousMode returns whether the SurfaceTexture is currently in
     // synchronous mode.
@@ -298,7 +301,31 @@
     // are freed except the current buffer.
     status_t drainQueueAndFreeBuffersLocked();
 
-    status_t setBufferCountServerLocked(int bufferCount);
+    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
+    // that will be used if the producer does not override the buffer slot
+    // count.
+    status_t setDefaultMaxBufferCountLocked(int count);
+
+    // getMinBufferCountLocked returns the minimum number of buffers allowed
+    // given the current BufferQueue state.
+    int getMinMaxBufferCountLocked() const;
+
+    // getMinUndequeuedBufferCountLocked returns the minimum number of buffers
+    // that must remain in a state other than DEQUEUED.
+    int getMinUndequeuedBufferCountLocked() const;
+
+    // getMaxBufferCountLocked returns the maximum number of buffers that can
+    // be allocated at once.  This value depends upon the following member
+    // variables:
+    //
+    //      mSynchronousMode
+    //      mMaxAcquiredBufferCount
+    //      mDefaultMaxBufferCount
+    //      mOverrideMaxBufferCount
+    //
+    // Any time one of these member variables is changed while a producer is
+    // connected, mDequeueCondition must be broadcast.
+    int getMaxBufferCountLocked() const;
 
     struct BufferSlot {
 
@@ -422,30 +449,27 @@
     // in requestBuffers() if a width and height of zero is specified.
     uint32_t mDefaultHeight;
 
-    // mMinUndequeuedBuffers is a constraint on the number of buffers
-    // not dequeued at any time
-    int mMinUndequeuedBuffers;
+    // mMaxAcquiredBufferCount is the number of buffers that the consumer may
+    // acquire at one time.  It defaults to 1 and can be changed by the
+    // consumer via the setMaxAcquiredBufferCount method, but this may only be
+    // done when no producer is connected to the BufferQueue.
+    //
+    // This value is used to derive the value returned for the
+    // MIN_UNDEQUEUED_BUFFERS query by the producer.
+    int mMaxAcquiredBufferCount;
 
-    // mMinAsyncBufferSlots is a constraint on the minimum mBufferCount
-    // when this BufferQueue is in asynchronous mode
-    int mMinAsyncBufferSlots;
+    // mDefaultMaxBufferCount is the default limit on the number of buffers
+    // that will be allocated at one time.  This default limit is set by the
+    // consumer.  The limit (as opposed to the default limit) may be
+    // overridden by the producer.
+    int mDefaultMaxBufferCount;
 
-    // mMinSyncBufferSlots is a constraint on the minimum mBufferCount
-    // when this BufferQueue is in synchronous mode
-    int mMinSyncBufferSlots;
-
-    // mBufferCount is the number of buffer slots that the client and server
-    // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
-    // by calling setBufferCount or setBufferCountServer
-    int mBufferCount;
-
-    // mClientBufferCount is the number of buffer slots requested by the client.
-    // The default is zero, which means the client doesn't care how many buffers
-    // there is.
-    int mClientBufferCount;
-
-    // mServerBufferCount buffer count requested by the server-side
-    int mServerBufferCount;
+    // mOverrideMaxBufferCount is the limit on the number of buffers that will
+    // be allocated at one time. This value is set by the image producer by
+    // calling setBufferCount. The default is zero, which means the producer
+    // doesn't care about the number of buffers in the pool. In that case
+    // mDefaultMaxBufferCount is used as the limit.
+    int mOverrideMaxBufferCount;
 
     // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
     // allocate new GraphicBuffer objects.
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 73214a4..a143d81 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -148,11 +148,6 @@
 public:
     ScreenshotClient();
 
-    // TODO: Remove me.  Do not use.
-    // This is a compatibility shim for one product whose drivers are depending on
-    // this legacy function (when they shouldn't).
-    status_t update();
-
     // frees the previous screenshot and capture a new one
     status_t update(const sp<IBinder>& display);
     status_t update(const sp<IBinder>& display,
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 98741c5..2570cd9 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -87,10 +87,10 @@
     // when finished with it.
     void setReleaseFence(int fenceFd);
 
-    // setBufferCountServer set the buffer count. If the client has requested
-    // a buffer count using setBufferCount, the server-buffer count will
-    // take effect once the client sets the count back to zero.
-    status_t setBufferCountServer(int bufferCount);
+    // setDefaultMaxBufferCount sets the default limit on the maximum number
+    // of buffers that will be allocated at one time. The image producer may
+    // override the limit.
+    status_t setDefaultMaxBufferCount(int bufferCount);
 
     // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix
     // associated with the texture image set by the most recent call to
diff --git a/include/media/hardware/HDCPAPI.h b/include/media/hardware/HDCPAPI.h
new file mode 100644
index 0000000..bb91540
--- /dev/null
+++ b/include/media/hardware/HDCPAPI.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012 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 HDCP_API_H_
+
+#define HDCP_API_H_
+
+#include <utils/Errors.h>
+
+namespace android {
+
+struct HDCPModule {
+    typedef void (*ObserverFunc)(int msg, int ext1, int ext2);
+
+    // The msg argument in calls to the observer notification function.
+    enum {
+        // Sent in response to a call to "HDCPModule::initAsync" once
+        // initialization has either been successfully completed,
+        // i.e. the HDCP session is now fully setup (AKE, Locality Check,
+        // SKE and any authentication with repeaters completed) or failed.
+        // ext1 should be a suitable error code (status_t), ext2 is
+        // unused.
+        HDCP_INITIALIZATION_COMPLETE,
+
+        // Sent upon completion of a call to "HDCPModule::shutdownAsync".
+        // ext1 should be a suitable error code, ext2 is unused.
+        HDCP_SHUTDOWN_COMPLETE,
+    };
+
+    // Module can call the notification function to signal completion/failure
+    // of asynchronous operations (such as initialization) or out of band
+    // events.
+    HDCPModule(ObserverFunc observerNotify);
+
+    virtual ~HDCPModule();
+
+    // Request to setup an HDCP session with the specified host listening
+    // on the specified port.
+    virtual status_t initAsync(const char *host, unsigned port) = 0;
+
+    // Request to shutdown the active HDCP session.
+    virtual status_t shutdownAsync() = 0;
+
+    // Encrypt a data according to the HDCP spec. The data is to be
+    // encrypted in-place, only size bytes of data should be read/write,
+    // even if the size is not a multiple of 128 bit (16 bytes).
+    // This operation is to be synchronous, i.e. this call does not return
+    // until outData contains size bytes of encrypted data.
+    // streamCTR will be assigned by the caller (to 0 for the first PES stream,
+    // 1 for the second and so on)
+    // inputCTR will be maintained by the callee for each PES stream.
+    virtual status_t encrypt(
+            const void *inData, size_t size, uint32_t streamCTR,
+            uint64_t *outInputCTR, void *outData) = 0;
+
+private:
+    HDCPModule(const HDCPModule &);
+    HDCPModule &operator=(const HDCPModule &);
+};
+
+}  // namespace android
+
+// A shared library exporting the following method should be included to
+// support HDCP functionality. The shared library must be called
+// "libstagefright_hdcp.so", it will be dynamically loaded into the
+// mediaserver process.
+extern "C" {
+    extern android::HDCPModule *createHDCPModule();
+}
+
+#endif  // HDCP_API_H_
+
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 218d929..57df39c 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -31,10 +31,11 @@
 
 BufferItemConsumer::BufferItemConsumer(uint32_t consumerUsage,
         int bufferCount, bool synchronousMode) :
-    ConsumerBase(new BufferQueue(true, bufferCount) )
+    ConsumerBase(new BufferQueue(true) )
 {
     mBufferQueue->setConsumerUsageBits(consumerUsage);
     mBufferQueue->setSynchronousMode(synchronousMode);
+    mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
 }
 
 BufferItemConsumer::~BufferItemConsumer() {
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 697635b..4640149 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -81,16 +81,13 @@
     }
 }
 
-BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount,
+BufferQueue::BufferQueue(bool allowSynchronousMode,
         const sp<IGraphicBufferAlloc>& allocator) :
     mDefaultWidth(1),
     mDefaultHeight(1),
-    mMinUndequeuedBuffers(bufferCount),
-    mMinAsyncBufferSlots(bufferCount + 1),
-    mMinSyncBufferSlots(bufferCount),
-    mBufferCount(mMinAsyncBufferSlots),
-    mClientBufferCount(0),
-    mServerBufferCount(mMinAsyncBufferSlots),
+    mMaxAcquiredBufferCount(1),
+    mDefaultMaxBufferCount(2),
+    mOverrideMaxBufferCount(0),
     mSynchronousMode(false),
     mAllowSynchronousMode(allowSynchronousMode),
     mConnectedApi(NO_CONNECTED_API),
@@ -120,37 +117,13 @@
     ST_LOGV("~BufferQueue");
 }
 
-status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
-    if (bufferCount > NUM_BUFFER_SLOTS)
+status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) {
+    if (count < 2 || count > NUM_BUFFER_SLOTS)
         return BAD_VALUE;
 
-    mServerBufferCount = bufferCount;
+    mDefaultMaxBufferCount = count;
+    mDequeueCondition.broadcast();
 
-    if (bufferCount == mBufferCount)
-        return OK;
-
-    if (!mClientBufferCount &&
-        bufferCount >= mBufferCount) {
-        // easy, we just have more buffers
-        mBufferCount = bufferCount;
-        mDequeueCondition.broadcast();
-    } else {
-        // we're here because we're either
-        // - reducing the number of available buffers
-        // - or there is a client-buffer-count in effect
-
-        // less than 2 buffers is never allowed
-        if (bufferCount < 2)
-            return BAD_VALUE;
-
-        // when there is non client-buffer-count in effect, the client is not
-        // allowed to dequeue more than one buffer at a time,
-        // so the next time they dequeue a buffer, we know that they don't
-        // own one. the actual resizing will happen during the next
-        // dequeueBuffer.
-
-        mDequeueCondition.broadcast();
-    }
     return OK;
 }
 
@@ -199,20 +172,19 @@
         }
 
         // Error out if the user has dequeued buffers
-        for (int i=0 ; i<mBufferCount ; i++) {
+        int maxBufferCount = getMaxBufferCountLocked();
+        for (int i=0 ; i<maxBufferCount; i++) {
             if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
                 ST_LOGE("setBufferCount: client owns some buffers");
                 return -EINVAL;
             }
         }
 
-        const int minBufferSlots = mSynchronousMode ?
-            mMinSyncBufferSlots : mMinAsyncBufferSlots;
+        const int minBufferSlots = getMinMaxBufferCountLocked();
         if (bufferCount == 0) {
-            mClientBufferCount = 0;
-            bufferCount = (mServerBufferCount >= minBufferSlots) ?
-                    mServerBufferCount : minBufferSlots;
-            return setBufferCountServerLocked(bufferCount);
+            mOverrideMaxBufferCount = 0;
+            mDequeueCondition.broadcast();
+            return OK;
         }
 
         if (bufferCount < minBufferSlots) {
@@ -223,11 +195,11 @@
 
         // here we're guaranteed that the client doesn't have dequeued buffers
         // and will release all of its buffer references.
+        //
+        // XXX: Should this use drainQueueAndFreeBuffersLocked instead?
         freeAllBuffersLocked();
-        mBufferCount = bufferCount;
-        mClientBufferCount = bufferCount;
+        mOverrideMaxBufferCount = bufferCount;
         mBufferHasBeenQueued = false;
-        mQueue.clear();
         mDequeueCondition.broadcast();
         listener = mConsumerListener;
     } // scope for lock
@@ -261,8 +233,7 @@
         value = mDefaultBufferFormat;
         break;
     case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-        value = mSynchronousMode ?
-                (mMinUndequeuedBuffers-1) : mMinUndequeuedBuffers;
+        value = getMinUndequeuedBufferCountLocked();
         break;
     case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
         value = (mQueue.size() >= 2);
@@ -282,9 +253,17 @@
         ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
         return NO_INIT;
     }
-    if (slot < 0 || mBufferCount <= slot) {
+    int maxBufferCount = getMaxBufferCountLocked();
+    if (slot < 0 || maxBufferCount <= slot) {
         ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
-                mBufferCount, slot);
+                maxBufferCount, slot);
+        return BAD_VALUE;
+    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+        // XXX: I vaguely recall there was some reason this can be valid, but
+        // for the life of me I can't recall under what circumstances that's
+        // the case.
+        ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
+                slot, mSlots[slot].mBufferState);
         return BAD_VALUE;
     }
     mSlots[slot].mRequestBufferCalled = true;
@@ -324,50 +303,22 @@
                 return NO_INIT;
             }
 
-            // We need to wait for the FIFO to drain if the number of buffer
-            // needs to change.
-            //
-            // The condition "number of buffers needs to change" is true if
-            // - the client doesn't care about how many buffers there are
-            // - AND the actual number of buffer is different from what was
-            //   set in the last setBufferCountServer()
-            //                         - OR -
-            //   setBufferCountServer() was set to a value incompatible with
-            //   the synchronization mode (for instance because the sync mode
-            //   changed since)
-            //
-            // As long as this condition is true AND the FIFO is not empty, we
-            // wait on mDequeueCondition.
+            const int maxBufferCount = getMaxBufferCountLocked();
 
-            const int minBufferCountNeeded = mSynchronousMode ?
-                    mMinSyncBufferSlots : mMinAsyncBufferSlots;
-
-            const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
-                    ((mServerBufferCount != mBufferCount) ||
-                            (mServerBufferCount < minBufferCountNeeded));
-
-            if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
-                // wait for the FIFO to drain
-                mDequeueCondition.wait(mMutex);
-                // NOTE: we continue here because we need to reevaluate our
-                // whole state (eg: we could be abandoned or disconnected)
-                continue;
-            }
-
-            if (numberOfBuffersNeedsToChange) {
-                // here we're guaranteed that mQueue is empty
-                freeAllBuffersLocked();
-                mBufferCount = mServerBufferCount;
-                if (mBufferCount < minBufferCountNeeded)
-                    mBufferCount = minBufferCountNeeded;
-                mBufferHasBeenQueued = false;
-                returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+            // Free up any buffers that are in slots beyond the max buffer
+            // count.
+            for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
+                assert(mSlots[i].mBufferState == BufferSlot::FREE);
+                if (mSlots[i].mGraphicBuffer != NULL) {
+                    freeBufferLocked(i);
+                    returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+                }
             }
 
             // look for a free buffer to give to the client
             found = INVALID_BUFFER_SLOT;
             dequeuedCount = 0;
-            for (int i = 0; i < mBufferCount; i++) {
+            for (int i = 0; i < maxBufferCount; i++) {
                 const int state = mSlots[i].mBufferState;
                 if (state == BufferSlot::DEQUEUED) {
                     dequeuedCount++;
@@ -397,29 +348,31 @@
 
             // clients are not allowed to dequeue more than one buffer
             // if they didn't set a buffer count.
-            if (!mClientBufferCount && dequeuedCount) {
+            if (!mOverrideMaxBufferCount && dequeuedCount) {
                 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
                         "setting the buffer count");
                 return -EINVAL;
             }
 
             // See whether a buffer has been queued since the last
-            // setBufferCount so we know whether to perform the
-            // mMinUndequeuedBuffers check below.
+            // setBufferCount so we know whether to perform the min undequeued
+            // buffers check below.
             if (mBufferHasBeenQueued) {
                 // make sure the client is not trying to dequeue more buffers
                 // than allowed.
-                const int avail = mBufferCount - (dequeuedCount+1);
-                if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) {
-                    ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded "
-                            "(dequeued=%d)",
-                            mMinUndequeuedBuffers-int(mSynchronousMode),
-                            dequeuedCount);
+                const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
+                const int minUndequeuedCount = getMinUndequeuedBufferCountLocked();
+                if (newUndequeuedCount < minUndequeuedCount) {
+                    ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
+                            "exceeded (dequeued=%d undequeudCount=%d)",
+                            minUndequeuedCount, dequeuedCount,
+                            newUndequeuedCount);
                     return -EBUSY;
                 }
             }
 
-            // if no buffer is found, wait for a buffer to be released
+            // If no buffer is found, wait for a buffer to be released or for
+            // the max buffer count to change.
             tryAgain = found == INVALID_BUFFER_SLOT;
             if (tryAgain) {
                 mDequeueCondition.wait(mMutex);
@@ -560,9 +513,10 @@
             ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
             return NO_INIT;
         }
-        if (buf < 0 || buf >= mBufferCount) {
+        int maxBufferCount = getMaxBufferCountLocked();
+        if (buf < 0 || buf >= maxBufferCount) {
             ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
-                    mBufferCount, buf);
+                    maxBufferCount, buf);
             return -EINVAL;
         } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
             ST_LOGE("queueBuffer: slot %d is not owned by the client "
@@ -656,9 +610,10 @@
         return;
     }
 
-    if (buf < 0 || buf >= mBufferCount) {
+    int maxBufferCount = getMaxBufferCountLocked();
+    if (buf < 0 || buf >= maxBufferCount) {
         ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
-                mBufferCount, buf);
+                maxBufferCount, buf);
         return;
     } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
         ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
@@ -778,10 +733,12 @@
        fifo.append(buffer);
     }
 
+    int maxBufferCount = getMaxBufferCountLocked();
+
     snprintf(buffer, SIZE,
-            "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
+            "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
             "default-format=%d, FIFO(%d)={%s}\n",
-            prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
+            prefix, maxBufferCount, mSynchronousMode, mDefaultWidth,
             mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string());
     result.append(buffer);
 
@@ -798,7 +755,7 @@
         }
     } stateName;
 
-    for (int i=0 ; i<mBufferCount ; i++) {
+    for (int i=0 ; i<maxBufferCount ; i++) {
         const BufferSlot& slot(mSlots[i]);
         snprintf(buffer, SIZE,
                 "%s%s[%02d] "
@@ -855,6 +812,23 @@
 status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
     ATRACE_CALL();
     Mutex::Autolock _l(mMutex);
+
+    // Check that the consumer doesn't currently have the maximum number of
+    // buffers acquired.  We allow the max buffer count to be exceeded by one
+    // buffer, so that the consumer can successfully set up the newly acquired
+    // buffer before releasing the old one.
+    int numAcquiredBuffers = 0;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
+            numAcquiredBuffers++;
+        }
+    }
+    if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) {
+        ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)",
+                numAcquiredBuffers, mMaxAcquiredBufferCount);
+        return INVALID_OPERATION;
+    }
+
     // check if queue is empty
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
@@ -991,10 +965,20 @@
     return OK;
 }
 
-status_t BufferQueue::setBufferCountServer(int bufferCount) {
+status_t BufferQueue::setDefaultMaxBufferCount(int bufferCount) {
     ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
-    return setBufferCountServerLocked(bufferCount);
+    return setDefaultMaxBufferCountLocked(bufferCount);
+}
+
+status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    if (mConnectedApi != NO_CONNECTED_API) {
+        return INVALID_OPERATION;
+    }
+    mMaxAcquiredBufferCount = maxAcquiredBuffers;
+    return OK;
 }
 
 void BufferQueue::freeAllBuffersExceptHeadLocked() {
@@ -1038,6 +1022,41 @@
     return err;
 }
 
+int BufferQueue::getMinMaxBufferCountLocked() const {
+    return getMinUndequeuedBufferCountLocked() + 1;
+}
+
+int BufferQueue::getMinUndequeuedBufferCountLocked() const {
+    return mSynchronousMode ? mMaxAcquiredBufferCount :
+            mMaxAcquiredBufferCount + 1;
+}
+
+int BufferQueue::getMaxBufferCountLocked() const {
+    int minMaxBufferCount = getMinMaxBufferCountLocked();
+
+    int maxBufferCount = mDefaultMaxBufferCount;
+    if (maxBufferCount < minMaxBufferCount) {
+        maxBufferCount = minMaxBufferCount;
+    }
+    if (mOverrideMaxBufferCount != 0) {
+        assert(mOverrideMaxBufferCount >= minMaxBufferCount);
+        maxBufferCount = mOverrideMaxBufferCount;
+    }
+
+    // Any buffers that are dequeued by the producer or sitting in the queue
+    // waiting to be consumed need to have their slots preserved.  Such
+    // buffers will temporarily keep the max buffer count up until the slots
+    // no longer need to be preserved.
+    for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
+        BufferSlot::BufferState state = mSlots[i].mBufferState;
+        if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
+            maxBufferCount = i + 1;
+        }
+    }
+
+    return maxBufferCount;
+}
+
 BufferQueue::ProxyConsumerListener::ProxyConsumerListener(
         const wp<BufferQueue::ConsumerListener>& consumerListener):
         mConsumerListener(consumerListener) {}
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 242ac45..fc4a854 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -30,7 +30,7 @@
 namespace android {
 
 CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) :
-    ConsumerBase(new BufferQueue(true, maxLockedBuffers) ),
+    ConsumerBase(new BufferQueue(true) ),
     mMaxLockedBuffers(maxLockedBuffers),
     mCurrentLockedBuffers(0)
 {
@@ -41,6 +41,7 @@
 
     mBufferQueue->setSynchronousMode(true);
     mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
+    mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers);
 }
 
 CpuConsumer::~CpuConsumer() {
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index a70a5e8..139f219 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -55,7 +55,7 @@
         status_t result = reply.readInt32();
         if (result == NO_ERROR) {
             graphicBuffer = new GraphicBuffer();
-            reply.read(*graphicBuffer);
+            result = reply.read(*graphicBuffer);
             // reply.readStrongBinder();
             // here we don't even have to read the BufferReference from
             // the parcel, it'll die with the parcel.
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 0ffa932..e4922a4 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -558,14 +558,6 @@
     : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
 }
 
-// TODO: Remove me.  Do not use.
-// This is a compatibility shim for one product whose drivers are depending on
-// this legacy function (when they shouldn't).
-status_t ScreenshotClient::update() {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    return update(sm->getBuiltInDisplay(0));
-}
-
 status_t ScreenshotClient::update(const sp<IBinder>& display) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == NULL) return NO_INIT;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index c0b20df..975eb23 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -125,9 +125,9 @@
     mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
 }
 
-status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
+status_t SurfaceTexture::setDefaultMaxBufferCount(int bufferCount) {
     Mutex::Autolock lock(mMutex);
-    return mBufferQueue->setBufferCountServer(bufferCount);
+    return mBufferQueue->setDefaultMaxBufferCount(bufferCount);
 }
 
 
@@ -288,7 +288,9 @@
         computeCurrentTransformMatrix();
     } else  {
         if (err < 0) {
-            ST_LOGE("updateTexImage failed on acquire %d", err);
+            ST_LOGE("updateTexImage: acquire failed: %s (%d)",
+                strerror(-err), err);
+            return err;
         }
         // We always bind the texture even if we don't update its contents.
         glBindTexture(mTexTarget, mTexName);
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 59b9efd..ec14a0d 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -241,7 +241,7 @@
     EXPECT_EQ(1, buf->height);
     EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
     ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
-    EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
+    EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8));
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
     EXPECT_EQ(16, buf->width);
     EXPECT_EQ(8, buf->height);
@@ -597,15 +597,15 @@
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
     mST->getTransformMatrix(mtx);
 
-    // This accounts for the 1 texel shrink for each edge that's included in the
+    // This accounts for the .5 texel shrink for each edge that's included in the
     // transform matrix to avoid texturing outside the crop region.
-    EXPECT_EQ(.375f, mtx[0]);
+    EXPECT_EQ(0.5, mtx[0]);
     EXPECT_EQ(0.f, mtx[1]);
     EXPECT_EQ(0.f, mtx[2]);
     EXPECT_EQ(0.f, mtx[3]);
 
     EXPECT_EQ(0.f, mtx[4]);
-    EXPECT_EQ(-.375f, mtx[5]);
+    EXPECT_EQ(-0.5, mtx[5]);
     EXPECT_EQ(0.f, mtx[6]);
     EXPECT_EQ(0.f, mtx[7]);
 
@@ -614,8 +614,8 @@
     EXPECT_EQ(1.f, mtx[10]);
     EXPECT_EQ(0.f, mtx[11]);
 
-    EXPECT_EQ(.125f, mtx[12]);
-    EXPECT_EQ(.5f, mtx[13]);
+    EXPECT_EQ(0.0625f, mtx[12]);
+    EXPECT_EQ(0.5625f, mtx[13]);
     EXPECT_EQ(0.f, mtx[14]);
     EXPECT_EQ(1.f, mtx[15]);
 }
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 04f4b55..212c6a7 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -711,7 +711,7 @@
     ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
             -1));
 
-    mST->updateTexImage();
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -757,7 +757,7 @@
     ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
             -1));
 
-    mST->updateTexImage();
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -817,7 +817,7 @@
         ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
                 buf->getNativeBuffer(), -1));
 
-        mST->updateTexImage();
+        ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
         glClearColor(0.2, 0.2, 0.2, 0.2);
         glClear(GL_COLOR_BUFFER_BIT);
@@ -848,7 +848,7 @@
     enum { numFrames = 1024 };
 
     ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
-    ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
+    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
             texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
     ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
@@ -966,7 +966,7 @@
         if (i > 1) {
             mFW->waitForFrame();
         }
-        mST->updateTexImage();
+        ASSERT_EQ(NO_ERROR, mST->updateTexImage());
         drawTexture();
 
         for (int j = 0; j < numTestPixels; j++) {
@@ -997,7 +997,7 @@
 
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
-    mST->updateTexImage();
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -1039,7 +1039,7 @@
 
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
 
-    mST->updateTexImage();
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -1196,7 +1196,7 @@
     EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
     EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
     mFW->waitForFrame();
-    EXPECT_EQ(OK,mST->updateTexImage());
+    EXPECT_EQ(OK, mST->updateTexImage());
     Rect r = mST->getCurrentCrop();
     assertRectEq(Rect(23, 78, 123, 477), r);
 
@@ -1230,7 +1230,7 @@
     EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
     EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
     mFW->waitForFrame();
-    EXPECT_EQ(OK,mST->updateTexImage());
+    EXPECT_EQ(OK, mST->updateTexImage());
     Rect r = mST->getCurrentCrop();
     // crop should be the same as crop (same aspect ratio)
     assertRectEq(Rect(10, 20, 330, 200), r);
@@ -1241,7 +1241,7 @@
     EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
     EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
     mFW->waitForFrame();
-    EXPECT_EQ(OK,mST->updateTexImage());
+    EXPECT_EQ(OK, mST->updateTexImage());
     r = mST->getCurrentCrop();
     // crop should be the same height, but have cropped left and right borders
     // offset is 30.6 px L+, R-
@@ -1253,7 +1253,7 @@
     EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
     EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
     mFW->waitForFrame();
-    EXPECT_EQ(OK,mST->updateTexImage());
+    EXPECT_EQ(OK, mST->updateTexImage());
     r = mST->getCurrentCrop();
     // crop should be the same width, but have cropped top and bottom borders
     // offset is 37.5 px
@@ -1321,7 +1321,7 @@
     };
 
     ASSERT_EQ(OK, mST->setSynchronousMode(true));
-    ASSERT_EQ(OK, mST->setBufferCountServer(2));
+    ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
 
     sp<Thread> pt(new ProducerThread(mANW));
     pt->run();
@@ -1420,6 +1420,9 @@
 
     mST->setDefaultBufferSize(texWidth, texHeight);
 
+    // This test requires 3 buffers to complete run on a single thread.
+    mST->setDefaultMaxBufferCount(3);
+
     // Do the producer side of things
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
             mProducerEglSurface, mProducerEglContext));
@@ -1453,8 +1456,9 @@
 
     glDisable(GL_SCISSOR_TEST);
 
-    mST->updateTexImage(); // Skip the first frame, which was empty
-    mST->updateTexImage();
+    // Skip the first frame, which was empty
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -1508,7 +1512,7 @@
                 mEglContext));
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         mFW->waitForFrame();
-        mST->updateTexImage();
+        ASSERT_EQ(NO_ERROR, mST->updateTexImage());
         buffers[i] = mST->getCurrentBuffer();
     }
 
@@ -1584,7 +1588,7 @@
 
 TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
     // This test requires 3 buffers to run on a single thread.
-    mST->setBufferCountServer(3);
+    mST->setDefaultMaxBufferCount(3);
 
     ASSERT_TRUE(mST->isSynchronousMode());
 
@@ -1611,6 +1615,9 @@
     enum { texWidth = 64 };
     enum { texHeight = 64 };
 
+    // This test requires 3 buffers to complete run on a single thread.
+    mST->setDefaultMaxBufferCount(3);
+
     // Set the user buffer size.
     native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight);
 
@@ -1639,8 +1646,9 @@
 
     glDisable(GL_SCISSOR_TEST);
 
-    mST->updateTexImage(); // Skip the first frame, which was empty
-    mST->updateTexImage();
+    // Skip the first frame, which was empty
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -1664,6 +1672,9 @@
     enum { texWidth = 64 };
     enum { texHeight = 16 };
 
+    // This test requires 3 buffers to complete run on a single thread.
+    mST->setDefaultMaxBufferCount(3);
+
     // Set the transform hint.
     mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
 
@@ -1696,8 +1707,9 @@
 
     glDisable(GL_SCISSOR_TEST);
 
-    mST->updateTexImage(); // Skip the first frame, which was empty
-    mST->updateTexImage();
+    // Skip the first frame, which was empty
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -1721,6 +1733,9 @@
     enum { texWidth = 64 };
     enum { texHeight = 16 };
 
+    // This test requires 3 buffers to complete run on a single thread.
+    mST->setDefaultMaxBufferCount(3);
+
     // Set the transform hint.
     mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
 
@@ -1753,8 +1768,9 @@
 
     glDisable(GL_SCISSOR_TEST);
 
-    mST->updateTexImage(); // Skip the first frame, which was empty
-    mST->updateTexImage();
+    // Skip the first frame, which was empty
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -1944,7 +1960,7 @@
     runProducerThread(new PT());
 
     mFC->waitForFrame();
-    mST->updateTexImage();
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
     mFC->finishFrame();
 
     // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
@@ -1964,7 +1980,7 @@
 
     mFC->waitForFrame();
     mFC->finishFrame();
-    mST->updateTexImage();
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
 }
@@ -1990,7 +2006,7 @@
     for (int i = 0; i < NUM_ITERATIONS; i++) {
         mFC->waitForFrame();
         ALOGV("+updateTexImage");
-        mST->updateTexImage();
+        ASSERT_EQ(NO_ERROR, mST->updateTexImage());
         ALOGV("-updateTexImage");
         mFC->finishFrame();
 
@@ -2020,7 +2036,7 @@
         mFC->waitForFrame();
         mFC->finishFrame();
         ALOGV("+updateTexImage");
-        mST->updateTexImage();
+        ASSERT_EQ(NO_ERROR, mST->updateTexImage());
         ALOGV("-updateTexImage");
 
         // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
@@ -2045,7 +2061,7 @@
     };
 
     ASSERT_EQ(OK, mST->setSynchronousMode(true));
-    ASSERT_EQ(OK, mST->setBufferCountServer(2));
+    ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
 
     runProducerThread(new PT());
 
@@ -2059,10 +2075,10 @@
     // We must call updateTexImage to consume the first frame so that the
     // SurfaceTexture is able to reduce the buffer count to 2.  This is because
     // the GL driver may dequeue a buffer when the EGLSurface is created, and
-    // that happens before we call setBufferCountServer.  It's possible that the
+    // that happens before we call setDefaultMaxBufferCount.  It's possible that the
     // driver does not dequeue a buffer at EGLSurface creation time, so we
     // cannot rely on this to cause the second dequeueBuffer call to block.
-    mST->updateTexImage();
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     mFC->waitForFrame();
     mFC->finishFrame();
@@ -2081,15 +2097,15 @@
     }
 
     // Consume the two pending buffers to unblock the producer thread.
-    mST->updateTexImage();
-    mST->updateTexImage();
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
 
     // Consume the remaining buffers from the producer thread.
     for (int i = 0; i < NUM_ITERATIONS-3; i++) {
         mFC->waitForFrame();
         mFC->finishFrame();
         ALOGV("+updateTexImage");
-        mST->updateTexImage();
+        ASSERT_EQ(NO_ERROR, mST->updateTexImage());
         ALOGV("-updateTexImage");
     }
 }
@@ -2586,7 +2602,7 @@
 TEST_F(SurfaceTextureMultiContextGLTest,
         UpdateTexImageSucceedsForBufferConsumedBeforeDetach) {
     ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
-    ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
+    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
 
     // produce two frames and consume them both on the primary context
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 57063e5..b9cab85 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -258,7 +258,12 @@
     mOwner = ownHandle;
 
     if (handle != 0) {
-        mBufferMapper.registerBuffer(handle);
+        status_t err = mBufferMapper.registerBuffer(handle);
+        if (err != NO_ERROR) {
+            ALOGE("unflatten: registerBuffer failed: %s (%d)",
+                    strerror(-err), err);
+            return err;
+        }
     }
 
     return NO_ERROR;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 6d33592..7fb1159 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -67,8 +67,7 @@
  */
 
 FramebufferSurface::FramebufferSurface():
-    ConsumerBase(new BufferQueue(true, NUM_FRAME_BUFFERS,
-            new GraphicBufferAlloc())),
+    ConsumerBase(new BufferQueue(true, new GraphicBufferAlloc())),
     fbDev(0),
     mCurrentBufferSlot(-1),
     mCurrentBuffer(0)
@@ -93,7 +92,7 @@
         mBufferQueue->setDefaultBufferFormat(fbDev->format);
         mBufferQueue->setDefaultBufferSize(fbDev->width, fbDev->height);
         mBufferQueue->setSynchronousMode(true);
-        mBufferQueue->setBufferCountServer(NUM_FRAME_BUFFERS);
+        mBufferQueue->setDefaultMaxBufferCount(NUM_FRAME_BUFFERS);
     } else {
         ALOGE("Couldn't get gralloc module");
     }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4c82f91..ea1bc54 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -104,9 +104,9 @@
 
 #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
 #warning "disabling triple buffering"
-    mSurfaceTexture->setBufferCountServer(2);
+    mSurfaceTexture->setDefaultMaxBufferCount(2);
 #else
-    mSurfaceTexture->setBufferCountServer(3);
+    mSurfaceTexture->setDefaultMaxBufferCount(3);
 #endif
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1162432..cd1b336 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -944,7 +944,7 @@
         if (!curr.isIdenticalTo(draw)) {
             mVisibleRegionsDirty = true;
             const size_t cc = curr.size();
-            const size_t dc = draw.size();
+                  size_t dc = draw.size();
 
             // find the displays that were removed
             // (ie: in drawing state but not in current state)
@@ -965,27 +965,27 @@
                     const wp<IBinder>& display(curr.keyAt(j));
                     if (state.surface->asBinder() != draw[i].surface->asBinder()) {
                         // changing the surface is like destroying and
-                        // recreating the DisplayDevice
-                        sp<SurfaceTextureClient> stc(
-                                new SurfaceTextureClient(state.surface));
-                        sp<DisplayDevice> disp = new DisplayDevice(this,
-                            state.type, display, stc, NULL, mEGLConfig);
+                        // recreating the DisplayDevice, so we just remove it
+                        // from the drawing state, so that it get re-added
+                        // below.
+                        mDisplays.removeItem(display);
+                        mDrawingState.displays.removeItemsAt(i);
+                        dc--; i--;
+                        // at this point we must loop to the next item
+                        continue;
+                    }
 
-                        disp->setLayerStack(state.layerStack);
-                        disp->setOrientation(state.orientation);
-                        // TODO: take viewport and frame into account
-                        mDisplays.replaceValueFor(display, disp);
-                    }
-                    if (state.layerStack != draw[i].layerStack) {
-                        const sp<DisplayDevice>& disp(getDisplayDevice(display));
-                        disp->setLayerStack(state.layerStack);
-                    }
-                    if (state.orientation != draw[i].orientation ||
-                        state.viewport != draw[i].viewport ||
-                        state.frame != draw[i].frame) {
-                        const sp<DisplayDevice>& disp(getDisplayDevice(display));
-                        disp->setOrientation(state.orientation);
-                        // TODO: take viewport and frame into account
+                    const sp<DisplayDevice>& disp(getDisplayDevice(display));
+                    if (disp != NULL) {
+                        if (state.layerStack != draw[i].layerStack) {
+                            disp->setLayerStack(state.layerStack);
+                        }
+                        if (state.orientation != draw[i].orientation ||
+                                state.viewport != draw[i].viewport ||
+                                state.frame != draw[i].frame) {
+                            disp->setOrientation(state.orientation);
+                            // TODO: take viewport and frame into account
+                        }
                     }
                 }
             }
@@ -995,12 +995,17 @@
             for (size_t i=0 ; i<cc ; i++) {
                 if (draw.indexOfKey(curr.keyAt(i)) < 0) {
                     const DisplayDeviceState& state(curr[i]);
-                    sp<SurfaceTextureClient> stc(
-                            new SurfaceTextureClient(state.surface));
-                    const wp<IBinder>& display(curr.keyAt(i));
-                    sp<DisplayDevice> disp = new DisplayDevice(this,
-                        state.type, display, stc, 0, mEGLConfig);
-                    mDisplays.add(display, disp);
+                    if (state.surface != NULL) {
+                        sp<SurfaceTextureClient> stc(
+                                new SurfaceTextureClient(state.surface));
+                        const wp<IBinder>& display(curr.keyAt(i));
+                        sp<DisplayDevice> disp = new DisplayDevice(this,
+                                state.type, display, stc, 0, mEGLConfig);
+                        disp->setLayerStack(state.layerStack);
+                        disp->setOrientation(state.orientation);
+                        // TODO: take viewport and frame into account
+                        mDisplays.add(display, disp);
+                    }
                 }
             }
         }
@@ -1264,15 +1269,13 @@
 
 void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
 {
+    const int32_t id = hw->getHwcDisplayId();
     HWComposer& hwc(getHwComposer());
-    int32_t id = hw->getHwcDisplayId();
     HWComposer::LayerListIterator cur = hwc.begin(id);
     const HWComposer::LayerListIterator end = hwc.end(id);
 
-    const bool hasGlesComposition = hwc.hasGlesComposition(id);
-    const bool hasHwcComposition = hwc.hasHwcComposition(id);
-    if (cur==end || hasGlesComposition) {
-
+    const bool hasGlesComposition = hwc.hasGlesComposition(id) || (cur==end);
+    if (hasGlesComposition) {
         DisplayDevice::makeCurrent(hw, mEGLContext);
 
         // set the frame buffer
@@ -1280,6 +1283,7 @@
         glLoadIdentity();
 
         // Never touch the framebuffer if we don't have any framebuffer layers
+        const bool hasHwcComposition = hwc.hasHwcComposition(id);
         if (hasHwcComposition) {
             // when using overlays, we assume a fully transparent framebuffer
             // NOTE: we could reduce how much we need to clear, for instance
@@ -1296,38 +1300,49 @@
                 drawWormhole(hw, region);
             }
         }
+    }
 
-        /*
-         * and then, render the layers targeted at the framebuffer
-         */
+    /*
+     * and then, render the layers targeted at the framebuffer
+     */
 
-        const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ());
-        const size_t count = layers.size();
-        const Transform& tr = hw->getTransform();
-        for (size_t i=0 ; i<count ; ++i) {
+    const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ());
+    const size_t count = layers.size();
+    const Transform& tr = hw->getTransform();
+    if (cur != end) {
+        // we're using h/w composer
+        for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) {
             const sp<LayerBase>& layer(layers[i]);
             const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
-            if (cur != end) {
-                // we're using h/w composer
-                if (!clip.isEmpty()) {
-                    if (cur->getCompositionType() == HWC_OVERLAY) {
-                        if (i && (cur->getHints() & HWC_HINT_CLEAR_FB)
-                                && layer->isOpaque()) {
+            if (!clip.isEmpty()) {
+                switch (cur->getCompositionType()) {
+                    case HWC_OVERLAY: {
+                        if ((cur->getHints() & HWC_HINT_CLEAR_FB)
+                                && i
+                                && layer->isOpaque()
+                                && hasGlesComposition) {
                             // never clear the very first layer since we're
                             // guaranteed the FB is already cleared
                             layer->clearWithOpenGL(hw, clip);
                         }
-                    } else {
-                        layer->draw(hw, clip);
+                        break;
                     }
-                    layer->setAcquireFence(hw, *cur);
+                    case HWC_FRAMEBUFFER: {
+                        layer->draw(hw, clip);
+                        break;
+                    }
                 }
-                ++cur;
-            } else {
-                // we're not using h/w composer
-                if (!clip.isEmpty()) {
-                    layer->draw(hw, clip);
-                }
+            }
+            layer->setAcquireFence(hw, *cur);
+        }
+    } else {
+        // we're not using h/w composer
+        for (size_t i=0 ; i<count ; ++i) {
+            const sp<LayerBase>& layer(layers[i]);
+            const Region clip(dirty.intersect(
+                    tr.transform(layer->visibleRegion)));
+            if (!clip.isEmpty()) {
+                layer->draw(hw, clip);
             }
         }
     }