SurfaceFlinger: Prevent deadlock by updating an atomic layer set.

Bug: 12934849

Change-Id: I9dede7316f1e967de4140bd731ac810115ea302f
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2d8084d..765f179 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -277,6 +277,11 @@
      */
     Rect getContentCrop() const;
 
+    /*
+     * Returns if a frame is queued.
+     */
+    bool hasQueuedFrame() const { return mQueuedFrames > 0; }
+
     // -----------------------------------------------------------------------
 
     void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index aeba720..cfb9d01 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1541,9 +1541,24 @@
 
     bool visibleRegions = false;
     const LayerVector& layers(mDrawingState.layersSortedByZ);
-    const size_t count = layers.size();
-    for (size_t i=0 ; i<count ; i++) {
+
+    // Store the set of layers that need updates. This set must not change as
+    // buffers are being latched, as this could result in a deadlock.
+    // Example: Two producers share the same command stream and:
+    // 1.) Layer 0 is latched
+    // 2.) Layer 0 gets a new frame
+    // 2.) Layer 1 gets a new frame
+    // 3.) Layer 1 is latched.
+    // Display is now waiting on Layer 1's frame, which is behind layer 0's
+    // second frame. But layer 0's second frame could be waiting on display.
+    Vector<Layer*> layersWithQueuedFrames;
+    for (size_t i = 0, count = layers.size(); i<count ; i++) {
         const sp<Layer>& layer(layers[i]);
+        if (layer->hasQueuedFrame())
+            layersWithQueuedFrames.push_back(layer.get());
+    }
+    for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
+        Layer* layer = layersWithQueuedFrames[i];
         const Region dirty(layer->latchBuffer(visibleRegions));
         const Layer::State& s(layer->getDrawingState());
         invalidateLayerStack(s.layerStack, dirty);