Re-jigger layers

 Bug: 15185239
 Bug: 15238382

 Make DeferredLayerUpdater ref counted so that
 HardwareLayer:finalizer() works non-crashily on
 leaked layers
 Give DeferredLayerUpdater the ability to have a layer destroyer
 set so that leaked layers can still be recycled on the
 RenderThread
 Order layer updates based off of pushLayerUpdate() calls to fix
 issue with nested layers

Change-Id: I4449cee607f7e5126e02fed7464cf48038e3dfdf
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 64a4c41..f1163e2 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -178,7 +178,7 @@
     private static EGLSurface sPbuffer;
     private static final Object[] sPbufferLock = new Object[0];
 
-    private List<HardwareLayer> mAttachedLayers = new ArrayList<HardwareLayer>();
+    private List<HardwareLayer> mLayerUpdates = new ArrayList<HardwareLayer>();
 
     private static class GLRendererEglContext extends ManagedEGLContext {
         final Handler mHandler = new Handler();
@@ -471,7 +471,7 @@
 
     @Override
     void pushLayerUpdate(HardwareLayer layer) {
-        mGlCanvas.pushLayerUpdate(layer);
+        mLayerUpdates.add(layer);
     }
 
     @Override
@@ -494,11 +494,6 @@
         return HardwareLayer.createDisplayListLayer(this, width, height);
     }
 
-    @Override
-    void onLayerCreated(HardwareLayer hardwareLayer) {
-        mAttachedLayers.add(hardwareLayer);
-    }
-
     boolean hasContext() {
         return sEgl != null && mEglContext != null
                 && mEglContext.equals(sEgl.eglGetCurrentContext());
@@ -509,11 +504,7 @@
         if (mGlCanvas != null) {
             mGlCanvas.cancelLayerUpdate(layer);
         }
-        if (hasContext()) {
-            long backingLayer = layer.detachBackingLayer();
-            nDestroyLayer(backingLayer);
-        }
-        mAttachedLayers.remove(layer);
+        mLayerUpdates.remove(layer);
     }
 
     @Override
@@ -1198,16 +1189,19 @@
 
     private void flushLayerChanges() {
         // Loop through and apply any pending layer changes
-        for (int i = 0; i < mAttachedLayers.size(); i++) {
-            HardwareLayer layer = mAttachedLayers.get(i);
+        for (int i = 0; i < mLayerUpdates.size(); i++) {
+            HardwareLayer layer = mLayerUpdates.get(i);
             layer.flushChanges();
             if (!layer.isValid()) {
                 // The layer was removed from mAttachedLayers, rewind i by 1
                 // Note that this shouldn't actually happen as View.getHardwareLayer()
                 // is already flushing for error checking reasons
                 i--;
+            } else if (layer.hasDisplayList()) {
+                mCanvas.pushLayerUpdate(layer);
             }
         }
+        mLayerUpdates.clear();
     }
 
     @Override
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 4d78733..652bcd2 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -22,6 +22,8 @@
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 
+import com.android.internal.util.VirtualRefBasePtr;
+
 /**
  * A hardware layer can be used to render graphics operations into a hardware
  * friendly buffer. For instance, with an OpenGL backend a hardware layer
@@ -36,7 +38,7 @@
     private static final int LAYER_TYPE_DISPLAY_LIST = 2;
 
     private HardwareRenderer mRenderer;
-    private Finalizer mFinalizer;
+    private VirtualRefBasePtr mFinalizer;
     private RenderNode mDisplayList;
     private final int mLayerType;
 
@@ -47,10 +49,7 @@
         }
         mRenderer = renderer;
         mLayerType = type;
-        mFinalizer = new Finalizer(deferredUpdater);
-
-        // Layer is considered initialized at this point, notify the HardwareRenderer
-        mRenderer.onLayerCreated(this);
+        mFinalizer = new VirtualRefBasePtr(deferredUpdater);
     }
 
     private void assertType(int type) {
@@ -59,6 +58,10 @@
         }
     }
 
+    boolean hasDisplayList() {
+        return mDisplayList != null;
+    }
+
     /**
      * Update the paint used when drawing this layer.
      *
@@ -66,7 +69,8 @@
      * @see View#setLayerPaint(android.graphics.Paint)
      */
     public void setLayerPaint(Paint paint) {
-        nSetLayerPaint(mFinalizer.mDeferredUpdater, paint.mNativePaint);
+        nSetLayerPaint(mFinalizer.get(), paint.mNativePaint);
+        mRenderer.pushLayerUpdate(this);
     }
 
     /**
@@ -75,7 +79,7 @@
      * @return True if the layer can be rendered into, false otherwise
      */
     public boolean isValid() {
-        return mFinalizer != null && mFinalizer.mDeferredUpdater != 0;
+        return mFinalizer != null && mFinalizer.get() != 0;
     }
 
     /**
@@ -91,35 +95,14 @@
             mDisplayList.destroyDisplayListData();
             mDisplayList = null;
         }
-        if (mRenderer != null) {
-            mRenderer.onLayerDestroyed(this);
-            mRenderer = null;
-        }
-        doDestroyLayerUpdater();
+        mRenderer.onLayerDestroyed(this);
+        mRenderer = null;
+        mFinalizer.release();
+        mFinalizer = null;
     }
 
     public long getDeferredLayerUpdater() {
-        return mFinalizer.mDeferredUpdater;
-    }
-
-    /**
-     * Destroys the deferred layer updater but not the backing layer. The
-     * backing layer is instead returned and is the caller's responsibility
-     * to destroy/recycle as appropriate.
-     *
-     * It is safe to call this in onLayerDestroyed only
-     */
-    public long detachBackingLayer() {
-        long backingLayer = nDetachBackingLayer(mFinalizer.mDeferredUpdater);
-        doDestroyLayerUpdater();
-        return backingLayer;
-    }
-
-    private void doDestroyLayerUpdater() {
-        if (mFinalizer != null) {
-            mFinalizer.destroy();
-            mFinalizer = null;
-        }
+        return mFinalizer.get();
     }
 
     public RenderNode startRecording() {
@@ -132,7 +115,7 @@
     }
 
     public void endRecording(Rect dirtyRect) {
-        nUpdateRenderLayer(mFinalizer.mDeferredUpdater, mDisplayList.getNativeDisplayList(),
+        nUpdateRenderLayer(mFinalizer.get(), mDisplayList.getNativeDisplayList(),
                 dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
         mRenderer.pushLayerUpdate(this);
     }
@@ -160,7 +143,7 @@
      *         match the desired values.
      */
     public boolean prepare(int width, int height, boolean isOpaque) {
-        return nPrepare(mFinalizer.mDeferredUpdater, width, height, isOpaque);
+        return nPrepare(mFinalizer.get(), width, height, isOpaque);
     }
 
     /**
@@ -169,7 +152,8 @@
      * @param matrix The transform to apply to the layer.
      */
     public void setTransform(Matrix matrix) {
-        nSetTransform(mFinalizer.mDeferredUpdater, matrix.native_instance);
+        nSetTransform(mFinalizer.get(), matrix.native_instance);
+        mRenderer.pushLayerUpdate(this);
     }
 
     /**
@@ -183,7 +167,7 @@
                 surface.detachFromGLContext();
                 // SurfaceTexture owns the texture name and detachFromGLContext
                 // should have deleted it
-                nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+                nOnTextureDestroyed(mFinalizer.get());
             }
         });
     }
@@ -200,24 +184,26 @@
             return;
         }
 
-        boolean success = nFlushChanges(mFinalizer.mDeferredUpdater);
+        boolean success = nFlushChanges(mFinalizer.get());
         if (!success) {
             destroy();
         }
     }
 
     public long getLayer() {
-        return nGetLayer(mFinalizer.mDeferredUpdater);
+        return nGetLayer(mFinalizer.get());
     }
 
     public void setSurfaceTexture(SurfaceTexture surface) {
         assertType(LAYER_TYPE_TEXTURE);
-        nSetSurfaceTexture(mFinalizer.mDeferredUpdater, surface, false);
+        nSetSurfaceTexture(mFinalizer.get(), surface, false);
+        mRenderer.pushLayerUpdate(this);
     }
 
     public void updateSurfaceTexture() {
         assertType(LAYER_TYPE_TEXTURE);
-        nUpdateSurfaceTexture(mFinalizer.mDeferredUpdater);
+        nUpdateSurfaceTexture(mFinalizer.get());
+        mRenderer.pushLayerUpdate(this);
     }
 
     /**
@@ -225,8 +211,8 @@
      */
     SurfaceTexture createSurfaceTexture() {
         assertType(LAYER_TYPE_TEXTURE);
-        SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.mDeferredUpdater));
-        nSetSurfaceTexture(mFinalizer.mDeferredUpdater, st, true);
+        SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.get()));
+        nSetSurfaceTexture(mFinalizer.get(), st, true);
         return st;
     }
 
@@ -258,15 +244,6 @@
     private static native long nCreateRenderLayer(int width, int height);
 
     private static native void nOnTextureDestroyed(long layerUpdater);
-    private static native long nDetachBackingLayer(long layerUpdater);
-
-    /** This also destroys the underlying layer if it is still attached.
-     *  Note it does not recycle the underlying layer, but instead queues it
-     *  for deferred deletion.
-     *  The HardwareRenderer should use detachBackingLayer() in the
-     *  onLayerDestroyed() callback to do recycling if desired.
-     */
-    private static native void nDestroyLayerUpdater(long layerUpdater);
 
     private static native boolean nPrepare(long layerUpdater, int width, int height, boolean isOpaque);
     private static native void nSetLayerPaint(long layerUpdater, long paint);
@@ -281,28 +258,4 @@
 
     private static native long nGetLayer(long layerUpdater);
     private static native int nGetTexName(long layerUpdater);
-
-    private static class Finalizer {
-        private long mDeferredUpdater;
-
-        public Finalizer(long deferredUpdater) {
-            mDeferredUpdater = deferredUpdater;
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            try {
-                destroy();
-            } finally {
-                super.finalize();
-            }
-        }
-
-        void destroy() {
-            if (mDeferredUpdater != 0) {
-                nDestroyLayerUpdater(mDeferredUpdater);
-                mDeferredUpdater = 0;
-            }
-        }
-    }
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 60f8ee3a..d71de9f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -323,12 +323,6 @@
     abstract void pushLayerUpdate(HardwareLayer layer);
 
     /**
-     * Tells the HardwareRenderer that a layer was created. The renderer should
-     * make sure to apply any pending layer changes at the start of a new frame
-     */
-    abstract void onLayerCreated(HardwareLayer hardwareLayer);
-
-    /**
      * Tells the HardwareRenderer that the layer is destroyed. The renderer
      * should remove the layer from any update queues.
      */
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index cac23a8..11db996 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -294,12 +294,7 @@
 
     @Override
     void pushLayerUpdate(HardwareLayer layer) {
-        // TODO: Remove this, it's not needed outside of GLRenderer
-    }
-
-    @Override
-    void onLayerCreated(HardwareLayer layer) {
-        // TODO: Is this actually useful?
+        nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
     }
 
     @Override
@@ -309,7 +304,7 @@
 
     @Override
     void onLayerDestroyed(HardwareLayer layer) {
-        nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
+        nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
     }
 
     @Override
@@ -398,7 +393,8 @@
     private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
     private static native long nCreateTextureLayer(long nativeProxy);
     private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
-    private static native void nDestroyLayer(long nativeProxy, long layer);
+    private static native void nPushLayerUpdate(long nativeProxy, long layer);
+    private static native void nCancelLayerUpdate(long nativeProxy, long layer);
 
     private static native void nFlushCaches(long nativeProxy, int flushMode);
 
diff --git a/core/java/com/android/internal/util/VirtualRefBasePtr.java b/core/java/com/android/internal/util/VirtualRefBasePtr.java
index 0bd4d3a..52306f1 100644
--- a/core/java/com/android/internal/util/VirtualRefBasePtr.java
+++ b/core/java/com/android/internal/util/VirtualRefBasePtr.java
@@ -32,11 +32,17 @@
         return mNativePtr;
     }
 
+    public void release() {
+        if (mNativePtr != 0) {
+            nDecStrong(mNativePtr);
+            mNativePtr = 0;
+        }
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
-            nDecStrong(mNativePtr);
-            mNativePtr = 0;
+            release();
         } finally {
             super.finalize();
         }
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index b2f17de..33a2705 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -55,9 +55,7 @@
     Layer* layer = LayerRenderer::createRenderLayer(width, height);
     if (!layer) return 0;
 
-    OpenGLRenderer* renderer = new LayerRenderer(layer);
-    renderer->initProperties();
-    return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer, renderer) );
+    return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer) );
 }
 
 static void android_view_HardwareLayer_onTextureDestroyed(JNIEnv* env, jobject clazz,
@@ -66,18 +64,6 @@
     layer->backingLayer()->clearTexture();
 }
 
-static jlong android_view_HardwareLayer_detachBackingLayer(JNIEnv* env, jobject clazz,
-        jlong layerUpdaterPtr) {
-    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
-    return reinterpret_cast<jlong>( layer->detachBackingLayer() );
-}
-
-static void android_view_HardwareLayer_destroyLayerUpdater(JNIEnv* env, jobject clazz,
-        jlong layerUpdaterPtr) {
-    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
-    delete layer;
-}
-
 static jboolean android_view_HardwareLayer_prepare(JNIEnv* env, jobject clazz,
         jlong layerUpdaterPtr, jint width, jint height, jboolean isOpaque) {
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
@@ -157,8 +143,6 @@
     { "nCreateTextureLayer",     "()J",        (void*) android_view_HardwareLayer_createTextureLayer },
     { "nCreateRenderLayer",      "(II)J",      (void*) android_view_HardwareLayer_createRenderLayer },
     { "nOnTextureDestroyed",     "(J)V",       (void*) android_view_HardwareLayer_onTextureDestroyed },
-    { "nDetachBackingLayer",     "(J)J",       (void*) android_view_HardwareLayer_detachBackingLayer },
-    { "nDestroyLayerUpdater",    "(J)V",       (void*) android_view_HardwareLayer_destroyLayerUpdater },
 
     { "nPrepare",                "(JIIZ)Z",    (void*) android_view_HardwareLayer_prepare },
     { "nSetLayerPaint",          "(JJ)V",      (void*) android_view_HardwareLayer_setLayerPaint },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index bd016fd..1397131 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -287,11 +287,18 @@
     return proxy->copyLayerInto(layer, bitmap);
 }
 
-static void android_view_ThreadedRenderer_destroyLayer(JNIEnv* env, jobject clazz,
+static void android_view_ThreadedRenderer_pushLayerUpdate(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong layerPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
-    proxy->destroyLayer(layer);
+    proxy->pushLayerUpdate(layer);
+}
+
+static void android_view_ThreadedRenderer_cancelLayerUpdate(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong layerPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+    proxy->cancelLayerUpdate(layer);
 }
 
 static void android_view_ThreadedRenderer_flushCaches(JNIEnv* env, jobject clazz,
@@ -347,7 +354,8 @@
     { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
     { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
-    { "nDestroyLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_destroyLayer },
+    { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
+    { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
     { "nFlushCaches", "(JI)V", (void*) android_view_ThreadedRenderer_flushCaches },
     { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
     { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 285c8c3..97e9bf6 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -22,14 +22,19 @@
 namespace android {
 namespace uirenderer {
 
-DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer)
+static void defaultLayerDestroyer(Layer* layer) {
+    Caches::getInstance().resourceCache.decrementRefcount(layer);
+}
+
+DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroyer)
         : mDisplayList(0)
         , mSurfaceTexture(0)
         , mTransform(0)
         , mNeedsGLContextAttach(false)
         , mUpdateTexImage(false)
         , mLayer(layer)
-        , mCaches(Caches::getInstance()) {
+        , mCaches(Caches::getInstance())
+        , mDestroyer(destroyer) {
     mWidth = mLayer->layer.getWidth();
     mHeight = mLayer->layer.getHeight();
     mBlend = mLayer->isBlend();
@@ -37,14 +42,16 @@
     mAlpha = mLayer->getAlpha();
     mMode = mLayer->getMode();
     mDirtyRect.setEmpty();
+
+    if (!mDestroyer) {
+        mDestroyer = defaultLayerDestroyer;
+    }
 }
 
 DeferredLayerUpdater::~DeferredLayerUpdater() {
     SkSafeUnref(mColorFilter);
     setTransform(0);
-    if (mLayer) {
-        mCaches.resourceCache.decrementRefcount(mLayer);
-    }
+    mDestroyer(mLayer);
 }
 
 void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index cc62caa..b7cfe80 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -30,13 +30,15 @@
 namespace android {
 namespace uirenderer {
 
+typedef void (*LayerDestroyer)(Layer* layer);
+
 // Container to hold the properties a layer should be set to at the start
 // of a render pass
-class DeferredLayerUpdater {
+class DeferredLayerUpdater : public VirtualLightRefBase {
 public:
     // Note that DeferredLayerUpdater assumes it is taking ownership of the layer
     // and will not call incrementRef on it as a result.
-    ANDROID_API DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer = 0);
+    ANDROID_API DeferredLayerUpdater(Layer* layer, LayerDestroyer = 0);
     ANDROID_API ~DeferredLayerUpdater();
 
     ANDROID_API bool setSize(uint32_t width, uint32_t height) {
@@ -83,12 +85,6 @@
         return mLayer;
     }
 
-    ANDROID_API Layer* detachBackingLayer() {
-        Layer* layer = mLayer;
-        mLayer = 0;
-        return layer;
-    }
-
 private:
     // Generic properties
     uint32_t mWidth;
@@ -111,6 +107,8 @@
     Layer* mLayer;
     Caches& mCaches;
 
+    LayerDestroyer mDestroyer;
+
     void doUpdateTexImage();
 };
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index f91e90e..9ebee1d 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -427,27 +427,11 @@
     mHaveNewSurface |= mGlobalContext->makeCurrent(mEglSurface);
 }
 
-void CanvasContext::prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters,
-        TreeInfo& info) {
-    LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot prepareDraw without a canvas!");
-    makeCurrent();
-
-    processLayerUpdates(layerUpdaters, info);
-    if (info.out.hasAnimations) {
-        // TODO: Uh... crap?
-    }
-    prepareTree(info);
-}
-
-void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
-        TreeInfo& info) {
-    for (size_t i = 0; i < layerUpdaters->size(); i++) {
-        DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
-        bool success = update->apply(info);
-        LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
-        if (update->backingLayer()->deferredUpdateScheduled) {
-            mCanvas->pushLayerUpdate(update->backingLayer());
-        }
+void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info) {
+    bool success = layerUpdater->apply(info);
+    LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
+    if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
+        mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
     }
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a04269b..00c5bf0 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -55,7 +55,8 @@
     void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
     void setOpaque(bool opaque);
     void makeCurrent();
-    void prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
+    void processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info);
+    void prepareTree(TreeInfo& info);
     void draw(Rect* dirty);
     void destroyCanvasAndSurface();
 
@@ -83,9 +84,6 @@
 private:
     friend class RegisterFrameCallbackTask;
 
-    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
-    void prepareTree(TreeInfo& info);
-
     void setSurface(ANativeWindow* window);
     void swapBuffers();
     void requireSurface();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 7ea358f..61d67ca 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -21,6 +21,7 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
+#include "../DeferredLayerUpdater.h"
 #include "../DisplayList.h"
 #include "../RenderNode.h"
 #include "CanvasContext.h"
@@ -47,17 +48,22 @@
     mContext = context;
 }
 
-void DrawFrameTask::addLayer(DeferredLayerUpdater* layer) {
-    LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to addLayer with!");
+void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
+    LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to pushLayerUpdate with!");
 
-    mLayers.push(layer);
+    for (size_t i = 0; i < mLayers.size(); i++) {
+        if (mLayers[i].get() == layer) {
+            return;
+        }
+    }
+    mLayers.push_back(layer);
 }
 
-void DrawFrameTask::removeLayer(DeferredLayerUpdater* layer) {
+void DrawFrameTask::removeLayerUpdate(DeferredLayerUpdater* layer) {
     for (size_t i = 0; i < mLayers.size(); i++) {
-        if (mLayers[i] == layer) {
-            mLayers.removeAt(i);
-            break;
+        if (mLayers[i].get() == layer) {
+            mLayers.erase(mLayers.begin() + i);
+            return;
         }
     }
 }
@@ -132,7 +138,16 @@
     mContext->makeCurrent();
     Caches::getInstance().textureCache.resetMarkInUse();
     initTreeInfo(info);
-    mContext->prepareDraw(&mLayers, info);
+
+    for (size_t i = 0; i < mLayers.size(); i++) {
+        mContext->processLayerUpdate(mLayers[i].get(), info);
+    }
+    mLayers.clear();
+    if (info.out.hasAnimations) {
+        // TODO: Uh... crap?
+    }
+    mContext->prepareTree(info);
+
     if (info.out.hasAnimations) {
         // TODO: dirty calculations, for now just do a full-screen inval
         mDirty.setEmpty();
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 30c8880..d4129b6 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -16,10 +16,11 @@
 #ifndef DRAWFRAMETASK_H
 #define DRAWFRAMETASK_H
 
+#include <vector>
+
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
 #include <utils/StrongPointer.h>
-#include <utils/Vector.h>
 
 #include "RenderTask.h"
 
@@ -56,8 +57,8 @@
 
     void setContext(RenderThread* thread, CanvasContext* context);
 
-    void addLayer(DeferredLayerUpdater* layer);
-    void removeLayer(DeferredLayerUpdater* layer);
+    void pushLayerUpdate(DeferredLayerUpdater* layer);
+    void removeLayerUpdate(DeferredLayerUpdater* layer);
 
     void setDirty(int left, int top, int right, int bottom);
     void setDensity(float density) { mDensity = density; }
@@ -83,13 +84,9 @@
     nsecs_t mFrameTimeNanos;
     nsecs_t mRecordDurationNanos;
     float mDensity;
+    std::vector< sp<DeferredLayerUpdater> > mLayers;
 
     int mSyncResult;
-
-    /*********************************************
-     *  Multi frame data
-     *********************************************/
-    Vector<DeferredLayerUpdater*> mLayers;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 77c0aa7..0901963 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -229,10 +229,21 @@
     postAndWait(task);
 }
 
+CREATE_BRIDGE1(destroyLayer, Layer* layer) {
+    LayerRenderer::destroyLayer(args->layer);
+    return NULL;
+}
+
+static void enqueueDestroyLayer(Layer* layer) {
+    SETUP_TASK(destroyLayer);
+    args->layer = layer;
+    RenderThread::getInstance().queue(task);
+}
+
 CREATE_BRIDGE3(createDisplayListLayer, CanvasContext* context, int width, int height) {
     Layer* layer = args->context->createRenderLayer(args->width, args->height);
     if (!layer) return 0;
-    return new DeferredLayerUpdater(layer);
+    return new DeferredLayerUpdater(layer, enqueueDestroyLayer);
 }
 
 DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) {
@@ -242,14 +253,13 @@
     args->context = mContext;
     void* retval = postAndWait(task);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
-    mDrawFrameTask.addLayer(layer);
     return layer;
 }
 
 CREATE_BRIDGE1(createTextureLayer, CanvasContext* context) {
     Layer* layer = args->context->createTextureLayer();
     if (!layer) return 0;
-    return new DeferredLayerUpdater(layer);
+    return new DeferredLayerUpdater(layer, enqueueDestroyLayer);
 }
 
 DeferredLayerUpdater* RenderProxy::createTextureLayer() {
@@ -257,15 +267,9 @@
     args->context = mContext;
     void* retval = postAndWait(task);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
-    mDrawFrameTask.addLayer(layer);
     return layer;
 }
 
-CREATE_BRIDGE1(destroyLayer, Layer* layer) {
-    LayerRenderer::destroyLayer(args->layer);
-    return NULL;
-}
-
 CREATE_BRIDGE3(copyLayerInto, CanvasContext* context, DeferredLayerUpdater* layer,
         SkBitmap* bitmap) {
     bool success = args->context->copyLayerInto(args->layer, args->bitmap);
@@ -280,11 +284,12 @@
     return (bool) postAndWait(task);
 }
 
-void RenderProxy::destroyLayer(DeferredLayerUpdater* layer) {
-    mDrawFrameTask.removeLayer(layer);
-    SETUP_TASK(destroyLayer);
-    args->layer = layer->detachBackingLayer();
-    post(task);
+void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
+    mDrawFrameTask.pushLayerUpdate(layer);
+}
+
+void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) {
+    mDrawFrameTask.removeLayerUpdate(layer);
 }
 
 CREATE_BRIDGE2(flushCaches, CanvasContext* context, Caches::FlushMode flushMode) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index c8d42ec..944ff9c 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -80,7 +80,8 @@
     ANDROID_API DeferredLayerUpdater* createDisplayListLayer(int width, int height);
     ANDROID_API DeferredLayerUpdater* createTextureLayer();
     ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
-    ANDROID_API void destroyLayer(DeferredLayerUpdater* layer);
+    ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer);
+    ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer);
 
     ANDROID_API void flushCaches(Caches::FlushMode flushMode);