Prevent crash when a single layer is enqueued several times for updates
Bug #8504687

Change-Id: I9b01bbc4e3f37af23dfe5e68d3d03ad3d238b94a
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 0267a66..63bb73f 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -165,6 +165,9 @@
             dirtyRect.right, dirtyRect.bottom, !isBlend());
 
     displayList->defer(deferredState, 0);
+
+    deferredUpdateScheduled = false;
+    displayList = NULL;
 }
 
 void Layer::flush() {
@@ -183,5 +186,21 @@
     }
 }
 
+void Layer::render() {
+    renderer->setViewport(layer.getWidth(), layer.getHeight());
+    renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
+            !isBlend());
+
+    renderer->drawDisplayList(displayList, dirtyRect, DisplayList::kReplayFlag_ClipChildren);
+
+    renderer->finish();
+    renderer = NULL;
+
+    dirtyRect.setEmpty();
+
+    deferredUpdateScheduled = false;
+    displayList = NULL;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 0e00191..27e0cf1 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -275,6 +275,7 @@
 
     void defer();
     void flush();
+    void render();
 
     /**
      * Bounds of the layer.
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index aeabe366..4a5785c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -540,13 +540,7 @@
         }
 
         if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
-            OpenGLRenderer* renderer = layer->renderer;
-            renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight());
-            renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom,
-                    !layer->isBlend());
-            renderer->drawDisplayList(layer->displayList, dirty,
-                    DisplayList::kReplayFlag_ClipChildren);
-            renderer->finish();
+            layer->render();
         } else {
             layer->defer();
         }
@@ -556,13 +550,6 @@
             startTiling(mSnapshot);
         }
 
-        if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
-            dirty.setEmpty();
-            layer->renderer = NULL;
-        }
-
-        layer->deferredUpdateScheduled = false;
-        layer->displayList = NULL;
         layer->debugDrawUpdate = mCaches.debugLayersUpdates;
 
         return true;
@@ -609,11 +596,12 @@
         // Note: it is very important to update the layers in reverse order
         for (int i = count - 1; i >= 0; i--) {
             sprintf(layerName, "Layer #%d", i);
-            startMark(layerName); {
-                Layer* layer = mLayerUpdates.itemAt(i);
-                layer->flush();
-                mCaches.resourceCache.decrementRefcount(layer);
-            }
+            startMark(layerName);
+
+            Layer* layer = mLayerUpdates.itemAt(i);
+            layer->flush();
+            mCaches.resourceCache.decrementRefcount(layer);
+
             endMark();
         }
 
@@ -626,6 +614,15 @@
 
 void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
     if (layer) {
+        // Make sure we don't introduce duplicates.
+        // SortedVector would do this automatically but we need to respect
+        // the insertion order. The linear search is not an issue since
+        // this list is usually very short (typically one item, at most a few)
+        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
+            if (mLayerUpdates.itemAt(i) == layer) {
+                return;
+            }
+        }
         mLayerUpdates.push_back(layer);
         mCaches.resourceCache.incrementRefcount(layer);
     }