gui: Surface::dequeueBuffer no locker holds mutex while blocking in binder

- This also fixes a hang in the camera service when trying to shut down
  if the producer is infinitely blocked while trying to get a new buffer.

Bug: 13250382
Change-Id: I32ca82162bb8645b97dbe084e13e05ca05529a42
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 975d005..b628a15 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -178,19 +178,38 @@
 int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
     ATRACE_CALL();
     ALOGV("Surface::dequeueBuffer");
-    Mutex::Autolock lock(mMutex);
+
+    int reqW;
+    int reqH;
+    bool swapIntervalZero;
+    uint32_t reqFormat;
+    uint32_t reqUsage;
+
+    {
+        Mutex::Autolock lock(mMutex);
+
+        reqW = mReqWidth ? mReqWidth : mUserWidth;
+        reqH = mReqHeight ? mReqHeight : mUserHeight;
+
+        swapIntervalZero = mSwapIntervalZero;
+        reqFormat = mReqFormat;
+        reqUsage = mReqUsage;
+    } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer
+
     int buf = -1;
-    int reqW = mReqWidth ? mReqWidth : mUserWidth;
-    int reqH = mReqHeight ? mReqHeight : mUserHeight;
     sp<Fence> fence;
-    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero,
-            reqW, reqH, mReqFormat, mReqUsage);
+    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,
+            reqW, reqH, reqFormat, reqUsage);
+
     if (result < 0) {
-        ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
-             "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
+        ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)"
+             "failed: %d", swapIntervalZero, reqW, reqH, reqFormat, reqUsage,
              result);
         return result;
     }
+
+    Mutex::Autolock lock(mMutex);
+
     sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
 
     // this should never happen