Merge "dumpstate: report per-partition MMC performance"
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index 9c91fc7..0f42613 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -148,6 +148,9 @@
     // Retrieve the sideband buffer stream, if any.
     virtual sp<NativeHandle> getSidebandStream() const;
 
+    // See IGraphicBufferConsumer::setShadowQueueSize
+    virtual void setShadowQueueSize(size_t size);
+
     // dump our state in a String
     virtual void dump(String8& result, const char* prefix) const;
 
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index e3624b7..a22015c 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -274,6 +274,13 @@
     // mBufferAge tracks the age of the contents of the most recently dequeued
     // buffer as the number of frames that have elapsed since it was last queued
     uint64_t mBufferAge;
+
+    // mConsumerHasShadowQueue determines if acquireBuffer should be more
+    // cautious about dropping buffers so that it always returns a buffer that
+    // is represented in the consumer's shadow queue.
+    bool mConsumerHasShadowQueue;
+    size_t mConsumerShadowQueueSize;
+
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 8f31b55..0be09a2 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -248,6 +248,11 @@
     // Retrieve the sideband buffer stream, if any.
     virtual sp<NativeHandle> getSidebandStream() const = 0;
 
+    // setShadowQueueSize notifies the BufferQueue that the consumer is
+    // shadowing its queue and allows it to limit the number of buffers it is
+    // permitted to drop during acquire so as to not get out of sync.
+    virtual void setShadowQueueSize(size_t size) = 0;
+
     // dump state into a string
     virtual void dump(String8& result, const char* prefix) const = 0;
 
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index c7d5e00..2deef0e 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -89,7 +89,20 @@
         // the timestamps are being auto-generated by Surface. If the app isn't
         // generating timestamps explicitly, it probably doesn't want frames to
         // be discarded based on them.
+        //
+        // If the consumer is shadowing our queue, we also make sure that we
+        // don't drop so many buffers that the consumer hasn't received the
+        // onFrameAvailable callback for the buffer it acquires. That is, we
+        // want the buffer we return to be in the consumer's shadow queue.
+        size_t droppableBuffers = mCore->mConsumerShadowQueueSize > 1 ?
+                mCore->mConsumerShadowQueueSize - 1 : 0;
         while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
+            if (mCore->mConsumerHasShadowQueue && droppableBuffers == 0) {
+                BQ_LOGV("acquireBuffer: no droppable buffers in consumer's"
+                        " shadow queue, continuing");
+                break;
+            }
+
             // If entry[1] is timely, drop entry[0] (and repeat). We apply an
             // additional criterion here: we only drop the earlier buffer if our
             // desiredPresent falls within +/- 1 second of the expected present.
@@ -124,6 +137,7 @@
             }
             mCore->mQueue.erase(front);
             front = mCore->mQueue.begin();
+            --droppableBuffers;
         }
 
         // See if the front buffer is due
@@ -537,6 +551,14 @@
     return mCore->mSidebandStream;
 }
 
+void BufferQueueConsumer::setShadowQueueSize(size_t size) {
+    ATRACE_CALL();
+    BQ_LOGV("setShadowQueueSize: %zu", size);
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mConsumerHasShadowQueue = true;
+    mCore->mConsumerShadowQueueSize = size;
+}
+
 void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
     mCore->dump(result, prefix);
 }
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 887f2cb..d0f7afa 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -71,7 +71,9 @@
     mIsAllocating(false),
     mIsAllocatingCondition(),
     mAllowAllocation(true),
-    mBufferAge(0)
+    mBufferAge(0),
+    mConsumerHasShadowQueue(false),
+    mConsumerShadowQueueSize(0)
 {
     if (allocator == NULL) {
         sp<ISurfaceComposer> composer(ComposerService::getComposerService());
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 6658ab1..480dfb6 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -52,6 +52,7 @@
     SET_CONSUMER_USAGE_BITS,
     SET_TRANSFORM_HINT,
     GET_SIDEBAND_STREAM,
+    SET_SHADOW_QUEUE_SIZE,
     DUMP,
 };
 
@@ -269,6 +270,17 @@
         return stream;
     }
 
+    virtual void setShadowQueueSize(size_t size) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+        data.writeInt64(static_cast<int64_t>(size));
+        status_t result = remote()->transact(SET_SHADOW_QUEUE_SIZE, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("setShadowQueueSize failed (%d)", result);
+            return;
+        }
+    }
+
     virtual void dump(String8& result, const char* prefix) const {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
@@ -423,6 +435,12 @@
             }
             return NO_ERROR;
         }
+        case SET_SHADOW_QUEUE_SIZE: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            size_t size = static_cast<size_t>(data.readInt64());
+            setShadowQueueSize(size);
+            return NO_ERROR;
+        }
         case DUMP: {
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             String8 result = data.readString8();
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 5d81f10..35aa7c7 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -267,6 +267,9 @@
     Mutex::Autolock lock(mMutex);
     int i = getSlotFromBufferLocked(buffer);
     if (i < 0) {
+        if (fenceFd >= 0) {
+            close(fenceFd);
+        }
         return i;
     }
     sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
@@ -308,6 +311,9 @@
     }
     int i = getSlotFromBufferLocked(buffer);
     if (i < 0) {
+        if (fenceFd >= 0) {
+            close(fenceFd);
+        }
         return i;
     }
 
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index b03e8d6..90a1c11 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -164,6 +164,9 @@
                 bounds.left, bounds.top, bounds.width(), bounds.height(),
                 ycbcr);
     } else {
+        if (fenceFd >= 0) {
+            close(fenceFd);
+        }
         return -EINVAL; // do not log failure
     }
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2944c63..9fb94dd 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -127,6 +127,10 @@
     mSurfaceFlingerConsumer->setContentsChangedListener(this);
     mSurfaceFlingerConsumer->setName(mName);
 
+    // Set the shadow queue size to 0 to notify the BufferQueue that we are
+    // shadowing it
+    mSurfaceFlingerConsumer->setShadowQueueSize(0);
+
 #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
 #warning "disabling triple buffering"
     mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
@@ -164,9 +168,10 @@
     { // Autolock scope
         Mutex::Autolock lock(mQueueItemLock);
         mQueueItems.push_back(item);
+        mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
+        android_atomic_inc(&mQueuedFrames);
     }
 
-    android_atomic_inc(&mQueuedFrames);
     mFlinger->signalLayerUpdate();
 }
 
@@ -1259,14 +1264,39 @@
             // layer update so we check again at the next opportunity.
             mFlinger->signalLayerUpdate();
             return outDirtyRegion;
+        } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
+            // If the buffer has been rejected, remove it from the shadow queue
+            // and return early
+            Mutex::Autolock lock(mQueueItemLock);
+
+            // Update the BufferQueue with the new shadow queue size after
+            // dropping this item
+            mQueueItems.removeAt(0);
+            mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
+
+            android_atomic_dec(&mQueuedFrames);
+            return outDirtyRegion;
         }
 
-        // Remove this buffer from our internal queue tracker
         { // Autolock scope
+            auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
             Mutex::Autolock lock(mQueueItemLock);
+
+            // Remove any stale buffers that have been dropped during
+            // updateTexImage
+            while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+                mQueueItems.removeAt(0);
+                android_atomic_dec(&mQueuedFrames);
+            }
+
+            // Update the BufferQueue with our new shadow queue size, since we
+            // have removed at least one item
             mQueueItems.removeAt(0);
+            mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
         }
 
+
         // Decrement the queued-frames count.  Signal another event if we
         // have more frames pending.
         if (android_atomic_dec(&mQueuedFrames) > 1) {
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index 3f50cb0..ffd9be2 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -16,14 +16,40 @@
 
 #include "Mesh.h"
 
+#include <utils/Log.h>
+
 namespace android {
 
 Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
     : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize),
       mPrimitive(primitive)
 {
-    mVertices = new float[(vertexSize + texCoordSize) * vertexCount];
-    mStride = mVertexSize + mTexCoordsSize;
+    if (vertexCount == 0) {
+        mVertices = new float[1];
+        mVertices[0] = 0.0f;
+        mStride = 0;
+        return;
+    }
+
+    size_t stride = vertexSize + texCoordSize;
+    size_t remainder = (stride * vertexCount) / vertexCount;
+    // Since all of the input parameters are unsigned, if stride is less than
+    // either vertexSize or texCoordSize, it must have overflowed. remainder
+    // will be equal to stride as long as stride * vertexCount doesn't overflow.
+    if ((stride < vertexSize) || (remainder != stride)) {
+        ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize,
+                texCoordSize);
+        mVertices = new float[1];
+        mVertices[0] = 0.0f;
+        mVertexCount = 0;
+        mVertexSize = 0;
+        mTexCoordsSize = 0;
+        mStride = 0;
+        return;
+    }
+
+    mVertices = new float[stride * vertexCount];
+    mStride = stride;
 }
 
 Mesh::~Mesh() {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index df4ac2e..715b92f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1994,18 +1994,25 @@
     engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
 }
 
-void SurfaceFlinger::addClientLayer(const sp<Client>& client,
+status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
         const sp<IBinder>& handle,
         const sp<IGraphicBufferProducer>& gbc,
         const sp<Layer>& lbc)
 {
+    // add this layer to the current state list
+    {
+        Mutex::Autolock _l(mStateLock);
+        if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) {
+            return NO_MEMORY;
+        }
+        mCurrentState.layersSortedByZ.add(lbc);
+        mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+    }
+
     // attach this layer to the client
     client->attachLayer(handle, lbc);
 
-    // add this layer to the current state list
-    Mutex::Autolock _l(mStateLock);
-    mCurrentState.layersSortedByZ.add(lbc);
-    mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+    return NO_ERROR;
 }
 
 status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
@@ -2262,10 +2269,16 @@
             break;
     }
 
-    if (result == NO_ERROR) {
-        addClientLayer(client, *handle, *gbp, layer);
-        setTransactionFlags(eTransactionNeeded);
+    if (result != NO_ERROR) {
+        return result;
     }
+
+    result = addClientLayer(client, *handle, *gbp, layer);
+    if (result != NO_ERROR) {
+        return result;
+    }
+
+    setTransactionFlags(eTransactionNeeded);
     return result;
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a06d1be..74f9031 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -144,6 +144,8 @@
     // every half hour.
     enum { LOG_FRAME_STATS_PERIOD =  30*60*60 };
 
+    static const size_t MAX_LAYERS = 4096;
+
     // We're reference counted, never destroy SurfaceFlinger directly
     virtual ~SurfaceFlinger();
 
@@ -305,7 +307,7 @@
     status_t removeLayer(const sp<Layer>& layer);
 
     // add a layer to SurfaceFlinger
-    void addClientLayer(const sp<Client>& client,
+    status_t addClientLayer(const sp<Client>& client,
             const sp<IBinder>& handle,
             const sp<IGraphicBufferProducer>& gbc,
             const sp<Layer>& lbc);
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 19c497a..a9a2958 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -74,7 +74,7 @@
     int buf = item.mBuf;
     if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
         releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR);
-        return NO_ERROR;
+        return BUFFER_REJECTED;
     }
 
     // Release the previous buffer.
@@ -125,6 +125,10 @@
     return mConsumer->getSidebandStream();
 }
 
+void SurfaceFlingerConsumer::setShadowQueueSize(size_t size) {
+    mConsumer->setShadowQueueSize(size);
+}
+
 // We need to determine the time when a buffer acquired now will be
 // displayed.  This can be calculated:
 //   time when previous buffer's actual-present fence was signaled
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 1aaba18..a90a8b9 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -28,6 +28,8 @@
  */
 class SurfaceFlingerConsumer : public GLConsumer {
 public:
+    static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
+
     struct ContentsChangedListener: public FrameAvailableListener {
         virtual void onSidebandStreamChanged() = 0;
     };
@@ -68,6 +70,9 @@
 
     sp<NativeHandle> getSidebandStream() const;
 
+    // See IGraphicBufferConsumer::setShadowQueueSize
+    void setShadowQueueSize(size_t size);
+
     nsecs_t computeExpectedPresent(const DispSync& dispSync);
 
 private: