Merge "Read leftover parcel data when a parceled Surface is found in the cache."
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 1eda646..50626a0 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -111,7 +111,12 @@
     //
     // This method will fail if the connect was previously called on the
     // SurfaceTexture and no corresponding disconnect call was made.
-    virtual status_t connect(int api) = 0;
+    //
+    // outWidth, outHeight and outTransform are filled with the default width
+    // and height of the window and current transform applied to buffers,
+    // respectively.
+    virtual status_t connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) = 0;
 
     // disconnect attempts to disconnect a client API from the SurfaceTexture.
     // Calling this method will cause any subsequent calls to other
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2a8e725..a6fb12e 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -106,7 +106,8 @@
     //
     // This method will fail if the connect was previously called on the
     // SurfaceTexture and no corresponding disconnect call was made.
-    virtual status_t connect(int api);
+    virtual status_t connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
 
     // disconnect attempts to disconnect a client API from the SurfaceTexture.
     // Calling this method will cause any subsequent calls to other
@@ -207,9 +208,28 @@
 
 protected:
 
-    // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
-    // all slots.
-    void freeAllBuffers();
+    // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
+    // for the given slot.
+    void freeBufferLocked(int index);
+
+    // freeAllBuffersLocked frees the resources (both GraphicBuffer and
+    // EGLImage) for all slots.
+    void freeAllBuffersLocked();
+
+    // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer
+    // and EGLImage) for all slots except the head of mQueue
+    void freeAllBuffersExceptHeadLocked();
+
+    // drainQueueLocked drains the buffer queue if we're in synchronous mode
+    // returns immediately otherwise. return NO_INIT if SurfaceTexture
+    // became abandoned or disconnected during this call.
+    status_t drainQueueLocked();
+
+    // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
+    // synchronous mode and free all buffers. In asynchronous mode, all buffers
+    // are freed except the current buffer.
+    status_t drainQueueAndFreeBuffersLocked();
+
     static bool isExternalFormat(uint32_t format);
 
 private:
diff --git a/include/utils/threads.h b/include/utils/threads.h
index c8e9c04..c84a9b4 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <time.h>
+#include <system/graphics.h>
 
 #if defined(HAVE_PTHREADS)
 # include <pthread.h>
@@ -42,8 +43,8 @@
      * ** Keep in sync with android.os.Process.java **
      * ***********************************************
      * 
-     * This maps directly to the "nice" priorites we use in Android.
-     * A thread priority should be chosen inverse-proportinally to
+     * This maps directly to the "nice" priorities we use in Android.
+     * A thread priority should be chosen inverse-proportionally to
      * the amount of work the thread is expected to do. The more work
      * a thread will do, the less favorable priority it should get so that 
      * it doesn't starve the system. Threads not behaving properly might
@@ -66,7 +67,7 @@
     ANDROID_PRIORITY_DISPLAY        =  -4,
     
     /* ui service treads might want to run at a urgent display (uncommon) */
-    ANDROID_PRIORITY_URGENT_DISPLAY =  -8,
+    ANDROID_PRIORITY_URGENT_DISPLAY =  HAL_PRIORITY_URGENT_DISPLAY,
     
     /* all normal audio threads */
     ANDROID_PRIORITY_AUDIO          = -16,
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index 55246dc..babd2c0 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -162,11 +162,15 @@
         return result;
     }
 
-    virtual status_t connect(int api) {
+    virtual status_t connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(api);
         remote()->transact(CONNECT, data, &reply);
+        *outWidth = reply.readInt32();
+        *outHeight = reply.readInt32();
+        *outTransform = reply.readInt32();
         status_t result = reply.readInt32();
         return result;
     }
@@ -283,7 +287,12 @@
         case CONNECT: {
             CHECK_INTERFACE(ISurfaceTexture, data, reply);
             int api = data.readInt32();
-            status_t res = connect(api);
+            uint32_t outWidth, outHeight, outTransform;
+            status_t res = connect(api,
+                    &outWidth, &outHeight, &outTransform);
+            reply->writeInt32(outWidth);
+            reply->writeInt32(outHeight);
+            reply->writeInt32(outTransform);
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 1a036ee..4afca68 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -104,7 +104,7 @@
 
 SurfaceTexture::~SurfaceTexture() {
     LOGV("SurfaceTexture::~SurfaceTexture");
-    freeAllBuffers();
+    freeAllBuffersLocked();
 }
 
 status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) {
@@ -154,7 +154,10 @@
         LOGE("setBufferCount: SurfaceTexture has been abandoned!");
         return NO_INIT;
     }
-
+    if (mConnectedApi == NO_CONNECTED_API) {
+        LOGE("setBufferCount: SurfaceTexture is not connected!");
+        return NO_INIT;
+    }
     if (bufferCount > NUM_BUFFER_SLOTS) {
         LOGE("setBufferCount: bufferCount larger than slots available");
         return BAD_VALUE;
@@ -185,7 +188,7 @@
 
     // here we're guaranteed that the client doesn't have dequeued buffers
     // and will release all of its buffer references.
-    freeAllBuffers();
+    freeAllBuffersLocked();
     mBufferCount = bufferCount;
     mClientBufferCount = bufferCount;
     mCurrentTexture = INVALID_BUFFER_SLOT;
@@ -214,6 +217,10 @@
         LOGE("requestBuffer: SurfaceTexture has been abandoned!");
         return NO_INIT;
     }
+    if (mConnectedApi == NO_CONNECTED_API) {
+        LOGE("requestBuffer: SurfaceTexture is not connected!");
+        return NO_INIT;
+    }
     if (slot < 0 || mBufferCount <= slot) {
         LOGE("requestBuffer: slot index out of range [0, %d]: %d",
                 mBufferCount, slot);
@@ -228,11 +235,6 @@
         uint32_t format, uint32_t usage) {
     LOGV("SurfaceTexture::dequeueBuffer");
 
-    if (mAbandoned) {
-        LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
-        return NO_INIT;
-    }
-
     if ((w && !h) || (!w && h)) {
         LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
         return BAD_VALUE;
@@ -246,10 +248,19 @@
     int dequeuedCount = 0;
     bool tryAgain = true;
     while (tryAgain) {
+        if (mAbandoned) {
+            LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+            return NO_INIT;
+        }
+        if (mConnectedApi == NO_CONNECTED_API) {
+            LOGE("dequeueBuffer: SurfaceTexture is not connected!");
+            return NO_INIT;
+        }
+
         // We need to wait for the FIFO to drain if the number of buffer
         // needs to change.
         //
-        // The condition "number of buffer needs to change" is true if
+        // 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()
@@ -261,31 +272,24 @@
         // As long as this condition is true AND the FIFO is not empty, we
         // wait on mDequeueCondition.
 
-        int minBufferCountNeeded = mSynchronousMode ?
+        const int minBufferCountNeeded = mSynchronousMode ?
                 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
 
-        if (!mClientBufferCount &&
+        const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
                 ((mServerBufferCount != mBufferCount) ||
-                        (mServerBufferCount < minBufferCountNeeded))) {
+                        (mServerBufferCount < minBufferCountNeeded));
+
+        if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
             // wait for the FIFO to drain
-            while (!mQueue.isEmpty()) {
-                mDequeueCondition.wait(mMutex);
-                if (mAbandoned) {
-                    LOGE("dequeueBuffer: SurfaceTexture was abandoned while "
-                            "blocked!");
-                    return NO_INIT;
-                }
-            }
-            minBufferCountNeeded = mSynchronousMode ?
-                    MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+            mDequeueCondition.wait(mMutex);
+            // NOTE: we continue here because we need to reevaluate our
+            // whole state (eg: we could be abandoned or disconnected)
+            continue;
         }
 
-
-        if (!mClientBufferCount &&
-                ((mServerBufferCount != mBufferCount) ||
-                        (mServerBufferCount < minBufferCountNeeded))) {
+        if (numberOfBuffersNeedsToChange) {
             // here we're guaranteed that mQueue is empty
-            freeAllBuffers();
+            freeAllBuffersLocked();
             mBufferCount = mServerBufferCount;
             if (mBufferCount < minBufferCountNeeded)
                 mBufferCount = minBufferCountNeeded;
@@ -414,9 +418,9 @@
 
     if (!enabled) {
         // going to asynchronous mode, drain the queue
-        while (mSynchronousMode != enabled && !mQueue.isEmpty()) {
-            mDequeueCondition.wait(mMutex);
-        }
+        err = drainQueueLocked();
+        if (err != NO_ERROR)
+            return err;
     }
 
     if (mSynchronousMode != enabled) {
@@ -442,6 +446,10 @@
             LOGE("queueBuffer: SurfaceTexture has been abandoned!");
             return NO_INIT;
         }
+        if (mConnectedApi == NO_CONNECTED_API) {
+            LOGE("queueBuffer: SurfaceTexture is not connected!");
+            return NO_INIT;
+        }
         if (buf < 0 || buf >= mBufferCount) {
             LOGE("queueBuffer: slot index out of range [0, %d]: %d",
                     mBufferCount, buf);
@@ -512,6 +520,10 @@
         LOGW("cancelBuffer: SurfaceTexture has been abandoned!");
         return;
     }
+    if (mConnectedApi == NO_CONNECTED_API) {
+        LOGE("cancelBuffer: SurfaceTexture is not connected!");
+        return;
+    }
 
     if (buf < 0 || buf >= mBufferCount) {
         LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
@@ -533,6 +545,10 @@
         LOGE("setCrop: SurfaceTexture has been abandoned!");
         return NO_INIT;
     }
+    if (mConnectedApi == NO_CONNECTED_API) {
+        LOGE("setCrop: SurfaceTexture is not connected!");
+        return NO_INIT;
+    }
     mNextCrop = crop;
     return OK;
 }
@@ -544,11 +560,16 @@
         LOGE("setTransform: SurfaceTexture has been abandoned!");
         return NO_INIT;
     }
+    if (mConnectedApi == NO_CONNECTED_API) {
+        LOGE("setTransform: SurfaceTexture is not connected!");
+        return NO_INIT;
+    }
     mNextTransform = transform;
     return OK;
 }
 
-status_t SurfaceTexture::connect(int api) {
+status_t SurfaceTexture::connect(int api,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
     LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
     Mutex::Autolock lock(mMutex);
 
@@ -569,6 +590,9 @@
                 err = -EINVAL;
             } else {
                 mConnectedApi = api;
+                *outWidth = mDefaultWidth;
+                *outHeight = mDefaultHeight;
+                *outTransform = 0;
             }
             break;
         default:
@@ -594,7 +618,9 @@
         case NATIVE_WINDOW_API_MEDIA:
         case NATIVE_WINDOW_API_CAMERA:
             if (mConnectedApi == api) {
+                drainQueueAndFreeBuffersLocked();
                 mConnectedApi = NO_CONNECTED_API;
+                mDequeueCondition.signal();
             } else {
                 LOGE("disconnect: connected to another api (cur=%d, req=%d)",
                         mConnectedApi, api);
@@ -628,6 +654,11 @@
     LOGV("SurfaceTexture::updateTexImage");
     Mutex::Autolock lock(mMutex);
 
+    if (mAbandoned) {
+        LOGE("calling updateTexImage() on an abandoned SurfaceTexture");
+        return NO_INIT;
+    }
+
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
     if (!mQueue.empty()) {
@@ -638,6 +669,10 @@
         EGLImageKHR image = mSlots[buf].mEglImage;
         if (image == EGL_NO_IMAGE_KHR) {
             EGLDisplay dpy = eglGetCurrentDisplay();
+            if (mSlots[buf].mGraphicBuffer == 0) {
+                LOGE("buffer at slot %d is null", buf);
+                return BAD_VALUE;
+            }
             image = createImage(dpy, mSlots[buf].mGraphicBuffer);
             mSlots[buf].mEglImage = image;
             mSlots[buf].mEglDisplay = dpy;
@@ -827,18 +862,66 @@
     mFrameAvailableListener = listener;
 }
 
-void SurfaceTexture::freeAllBuffers() {
+void SurfaceTexture::freeBufferLocked(int i) {
+    mSlots[i].mGraphicBuffer = 0;
+    mSlots[i].mBufferState = BufferSlot::FREE;
+    if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
+        mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+        mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+void SurfaceTexture::freeAllBuffersLocked() {
+    LOGW_IF(!mQueue.isEmpty(),
+            "freeAllBuffersLocked called but mQueue is not empty");
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        mSlots[i].mGraphicBuffer = 0;
-        mSlots[i].mBufferState = BufferSlot::FREE;
-        if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
-            mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
-            mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+        freeBufferLocked(i);
+    }
+}
+
+void SurfaceTexture::freeAllBuffersExceptHeadLocked() {
+    LOGW_IF(!mQueue.isEmpty(),
+            "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
+    int head = -1;
+    if (!mQueue.empty()) {
+        Fifo::iterator front(mQueue.begin());
+        head = *front;
+    }
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (i != head) {
+            freeBufferLocked(i);
         }
     }
 }
 
+status_t SurfaceTexture::drainQueueLocked() {
+    while (mSynchronousMode && !mQueue.isEmpty()) {
+        mDequeueCondition.wait(mMutex);
+        if (mAbandoned) {
+            LOGE("drainQueueLocked: SurfaceTexture has been abandoned!");
+            return NO_INIT;
+        }
+        if (mConnectedApi == NO_CONNECTED_API) {
+            LOGE("drainQueueLocked: SurfaceTexture is not connected!");
+            return NO_INIT;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t SurfaceTexture::drainQueueAndFreeBuffersLocked() {
+    status_t err = drainQueueLocked();
+    if (err == NO_ERROR) {
+        if (mSynchronousMode) {
+            freeAllBuffersLocked();
+        } else {
+            freeAllBuffersExceptHeadLocked();
+        }
+    }
+    return err;
+}
+
 EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
         const sp<GraphicBuffer>& graphicBuffer) {
     EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
@@ -908,9 +991,10 @@
 
 void SurfaceTexture::abandon() {
     Mutex::Autolock lock(mMutex);
-    freeAllBuffers();
+    mQueue.clear();
     mAbandoned = true;
     mCurrentTextureBuf.clear();
+    freeAllBuffersLocked();
     mDequeueCondition.signal();
 }
 
@@ -966,13 +1050,24 @@
     for (int i=0 ; i<mBufferCount ; i++) {
         const BufferSlot& slot(mSlots[i]);
         snprintf(buffer, SIZE,
-                "%s%s[%02d] state=%-8s, crop=[%d,%d,%d,%d], transform=0x%02x, "
-                "timestamp=%lld\n",
-                prefix, (i==mCurrentTexture)?">":" ", i, stateName(slot.mBufferState),
+                "%s%s[%02d] "
+                "state=%-8s, crop=[%d,%d,%d,%d], "
+                "transform=0x%02x, timestamp=%lld",
+                prefix, (i==mCurrentTexture)?">":" ", i,
+                stateName(slot.mBufferState),
                 slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, slot.mCrop.bottom,
                 slot.mTransform, slot.mTimestamp
         );
         result.append(buffer);
+
+        const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
+        if (buf != NULL) {
+            snprintf(buffer, SIZE,
+                    ", %p [%4ux%4u:%4u,%3X]",
+                    buf->handle, buf->width, buf->height, buf->stride, buf->format);
+            result.append(buffer);
+        }
+        result.append("\n");
     }
 }
 
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index d1037de..e91be84 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -385,7 +385,8 @@
 int SurfaceTextureClient::connect(int api) {
     LOGV("SurfaceTextureClient::connect");
     Mutex::Autolock lock(mMutex);
-    int err = mSurfaceTexture->connect(api);
+    int err = mSurfaceTexture->connect(api,
+            &mDefaultWidth, &mDefaultHeight, &mTransformHint);
     if (!err && api == NATIVE_WINDOW_API_CPU) {
         mConnectedToCpu = true;
     }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 383c045..505c843 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -533,7 +533,7 @@
     }
     snprintf(buffer, SIZE,
             "      "
-            "format=%2d, activeBuffer=[%3ux%3u:%3u,%3u],"
+            "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
             " freezeLock=%p, queued-frames=%d\n",
             mFormat, w0, h0, s0,f0,
             getFreezeLock().get(), mQueuedFrames);
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 5973e76..79cd0c3 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -86,9 +86,19 @@
     return res;
 }
 
-status_t SurfaceTextureLayer::connect(int api) {
-    status_t err = SurfaceTexture::connect(api);
+status_t SurfaceTextureLayer::connect(int api,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+    status_t err = SurfaceTexture::connect(api,
+            outWidth, outHeight, outTransform);
     if (err == NO_ERROR) {
+        sp<Layer> layer(mLayer.promote());
+        if (layer != NULL) {
+            uint32_t orientation = layer->getOrientation();
+            if (orientation & Transform::ROT_INVALID) {
+                orientation = 0;
+            }
+            *outTransform = orientation;
+        }
         switch(api) {
             case NATIVE_WINDOW_API_MEDIA:
             case NATIVE_WINDOW_API_CAMERA:
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
index 5d328b7..9508524 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.h
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -51,7 +51,8 @@
     virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
             uint32_t format, uint32_t usage);
 
-    virtual status_t connect(int api);
+    virtual status_t connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
 };
 
 // ---------------------------------------------------------------------------