Delete display list objects and resources on the UI thread
Bug #6073717
Bug #6065504
Bug #6026515
Bug #5971725

Prior to this patch, the destructor of DisplayList would always run
on the finalizer thread. This could cause a race condition if the UI
thread was busy rendering display lists at the same time leading to
various random native crashes.

Change-Id: Ie11108e3b1538d4b358a1a8b4cce1b2d33152d0c
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 77a6e52..8e5db36 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -679,7 +679,7 @@
 
 static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
         jobject clazz, DisplayList* displayList) {
-    delete displayList;
+    DisplayList::destroyDisplayListDeferred(displayList);
 }
 
 static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 0ef8469..123695a 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -20,6 +20,7 @@
 #include <utils/String8.h>
 
 #include "Caches.h"
+#include "DisplayListRenderer.h"
 #include "Properties.h"
 #include "LayerRenderer.h"
 
@@ -199,6 +200,13 @@
         LayerRenderer::destroyLayer(layer);
     }
     mLayerGarbage.clear();
+
+    count = mDisplayListGarbage.size();
+    for (size_t i = 0; i < count; i++) {
+        DisplayList* displayList = mDisplayListGarbage.itemAt(i);
+        delete displayList;
+    }
+    mDisplayListGarbage.clear();
 }
 
 void Caches::deleteLayerDeferred(Layer* layer) {
@@ -206,6 +214,11 @@
     mLayerGarbage.push(layer);
 }
 
+void Caches::deleteDisplayListDeferred(DisplayList* displayList) {
+    Mutex::Autolock _l(mGarbageLock);
+    mDisplayListGarbage.push(displayList);
+}
+
 void Caches::flush(FlushMode mode) {
     FLUSH_LOGD("Flushing caches (mode %d)", mode);
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index f8c7bcc..65ff9ad 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -90,6 +90,8 @@
 // Caches
 ///////////////////////////////////////////////////////////////////////////////
 
+class DisplayList;
+
 class ANDROID_API Caches: public Singleton<Caches> {
     Caches();
 
@@ -141,6 +143,11 @@
      */
     void deleteLayerDeferred(Layer* layer);
 
+    /*
+     * Can be used to delete a display list from a non EGL thread.
+     */
+    void deleteDisplayListDeferred(DisplayList* layer);
+
     /**
      * Binds the VBO used to render simple textured quads.
      */
@@ -269,6 +276,7 @@
 
     mutable Mutex mGarbageLock;
     Vector<Layer*> mLayerGarbage;
+    Vector<DisplayList*> mDisplayListGarbage;
 
     DebugLevel mDebugLevel;
     bool mInitialized;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index babfd04..d9b0e5a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -101,6 +101,13 @@
     clearResources();
 }
 
+void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
+    if (displayList) {
+        DISPLAY_LIST_LOGD("Deferring display list destruction");
+        Caches::getInstance().deleteDisplayListDeferred(displayList);
+    }
+}
+
 void DisplayList::clearResources() {
     sk_free((void*) mReader.base());
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 96b87cc..02f8438 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -119,16 +119,16 @@
 
     static const char* OP_NAMES[];
 
-    void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
-
     ANDROID_API size_t getSize();
+    ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList);
+    ANDROID_API static void outputLogBuffer(int fd);
+
+    void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
 
     bool replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
 
     void output(OpenGLRenderer& renderer, uint32_t level = 0);
 
-    ANDROID_API static void outputLogBuffer(int fd);
-
     void setRenderable(bool renderable) {
         mIsRenderable = renderable;
     }