Refcount RenderNode

Change-Id: I7a86db8acc2b78ef33d987a43a119f5933d7d752
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 477d691..df2123b 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -315,24 +315,15 @@
     pathCache.clearGarbage();
     patchCache.clearGarbage();
 
-    Vector<RenderNode*> displayLists;
     Vector<Layer*> layers;
 
     { // scope for the lock
         Mutex::Autolock _l(mGarbageLock);
-        displayLists = mDisplayListGarbage;
         layers = mLayerGarbage;
-        mDisplayListGarbage.clear();
         mLayerGarbage.clear();
     }
 
-    size_t count = displayLists.size();
-    for (size_t i = 0; i < count; i++) {
-        RenderNode* displayList = displayLists.itemAt(i);
-        delete displayList;
-    }
-
-    count = layers.size();
+    size_t count = layers.size();
     for (size_t i = 0; i < count; i++) {
         Layer* layer = layers.itemAt(i);
         delete layer;
@@ -345,11 +336,6 @@
     mLayerGarbage.push(layer);
 }
 
-void Caches::deleteDisplayListDeferred(RenderNode* 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 50c5fef..ba3ccaf 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -166,11 +166,6 @@
      */
     void deleteLayerDeferred(Layer* layer);
 
-    /*
-     * Can be used to delete a display list from a non EGL thread.
-     */
-    void deleteDisplayListDeferred(RenderNode* layer);
-
     /**
      * Binds the VBO used to render simple textured quads.
      */
@@ -420,7 +415,6 @@
 
     mutable Mutex mGarbageLock;
     Vector<Layer*> mLayerGarbage;
-    Vector<RenderNode*> mDisplayListGarbage;
 
     DebugLevel mDebugLevel;
     bool mInitialized;
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 5b4e03f..ce711b6 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -68,13 +68,13 @@
     mLayer->setColorFilter(mColorFilter);
     mLayer->setAlpha(mAlpha, mMode);
 
-    if (mDisplayList) {
+    if (mDisplayList.get()) {
         if (mWidth != mLayer->layer.getWidth() || mHeight != mLayer->layer.getHeight()) {
             success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
         }
         mLayer->setBlend(mBlend);
         mDisplayList->updateProperties();
-        mLayer->updateDeferred(mDisplayList,
+        mLayer->updateDeferred(mDisplayList.get(),
                 mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
         mDirtyRect.setEmpty();
         mDisplayList = 0;
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 10fa264..ce08c2d 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -101,7 +101,7 @@
     // Layer type specific properties
     // displayList and surfaceTexture are mutually exclusive, only 1 may be set
     // dirtyRect is only valid if displayList is set
-    RenderNode* mDisplayList;
+    sp<RenderNode> mDisplayList;
     Rect mDirtyRect;
     sp<GLConsumer> mSurfaceTexture;
     SkMatrix* mTransform;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 9e6a96d..a5d8dcb 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -29,6 +29,13 @@
 namespace android {
 namespace uirenderer {
 
+DisplayListData::DisplayListData() : projectionReceiveIndex(-1), functorCount(0), hasDrawOps(false) {
+}
+
+DisplayListData::~DisplayListData() {
+    cleanupResources();
+}
+
 void DisplayListData::cleanupResources() {
     Caches& caches = Caches::getInstance();
     caches.unregisterFunctors(functorCount);
@@ -91,5 +98,12 @@
     layers.clear();
 }
 
+void DisplayListData::addChild(DrawDisplayListOp* op) {
+    LOG_ALWAYS_FATAL_IF(!op->renderNode(), "DrawDisplayListOp with no render node!");
+
+    mChildren.push(op);
+    mReferenceHolders.push(op->renderNode());
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index df5cba6..fe70d13 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -41,6 +41,7 @@
 #include "Matrix.h"
 #include "DeferredDisplayList.h"
 #include "RenderProperties.h"
+#include "utils/VirtualLightRefBase.h"
 
 class SkBitmap;
 class SkPaint;
@@ -106,8 +107,8 @@
  */
 class DisplayListData {
 public:
-    DisplayListData() : projectionReceiveIndex(-1), functorCount(0), hasDrawOps(false) {}
-    virtual ~DisplayListData() { cleanupResources(); }
+    DisplayListData();
+    ~DisplayListData();
 
     // allocator into which all ops were allocated
     LinearAllocator allocator;
@@ -115,9 +116,6 @@
     // pointers to all ops within display list, pointing into allocator data
     Vector<DisplayListOp*> displayListOps;
 
-    // list of children display lists for quick, non-drawing traversal
-    Vector<DrawDisplayListOp*> children;
-
     // index of DisplayListOp restore, after which projected descendents should be drawn
     int projectionReceiveIndex;
 
@@ -139,7 +137,15 @@
         return !displayListOps.size();
     }
 
+    void addChild(DrawDisplayListOp* childOp);
+    const Vector<DrawDisplayListOp*>& children() { return mChildren; }
+
 private:
+    Vector< sp<VirtualLightRefBase> > mReferenceHolders;
+
+    // list of children display lists for quick, non-drawing traversal
+    Vector<DrawDisplayListOp*> mChildren;
+
     void cleanupResources();
 };
 
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 5fa8f1d..06f675e 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1523,6 +1523,8 @@
 
     virtual const char* name() { return "DrawDisplayList"; }
 
+    RenderNode* renderNode() { return mDisplayList; }
+
 private:
     RenderNode* mDisplayList;
     const int mFlags;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 78c97e1..a84aa6b 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -191,7 +191,7 @@
     DrawDisplayListOp* op = new (alloc()) DrawDisplayListOp(displayList,
             flags, *currentTransform());
     addDrawOp(op);
-    mDisplayListData->children.push(op);
+    mDisplayListData->addChild(op);
     if (displayList->isProjectionReceiver()) {
         mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
     }
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 27409a2..bfe4eda 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -140,6 +140,15 @@
     }
 }
 
+void Layer::updateDeferred(RenderNode* displayList,
+        int left, int top, int right, int bottom) {
+    requireRenderer();
+    this->displayList = displayList;
+    const Rect r(left, top, right, bottom);
+    dirtyRect.unionWith(r);
+    deferredUpdateScheduled = true;
+}
+
 void Layer::setPaint(const SkPaint* paint) {
     OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
     setColorFilter((paint) ? paint->getColorFilter() : NULL);
@@ -244,7 +253,7 @@
     renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
             !isBlend());
 
-    renderer->drawDisplayList(displayList, dirtyRect, RenderNode::kReplayFlag_ClipChildren);
+    renderer->drawDisplayList(displayList.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);
 
     renderer->finish();
 
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index b428404..5375b45 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -19,6 +19,7 @@
 
 #include <cutils/compiler.h>
 #include <sys/types.h>
+#include <utils/StrongPointer.h>
 
 #include <GLES2/gl2.h>
 
@@ -85,13 +86,7 @@
     }
 
     void updateDeferred(RenderNode* displayList,
-            int left, int top, int right, int bottom) {
-        requireRenderer();
-        this->displayList = displayList;
-        const Rect r(left, top, right, bottom);
-        dirtyRect.unionWith(r);
-        deferredUpdateScheduled = true;
-    }
+            int left, int top, int right, int bottom);
 
     inline uint32_t getWidth() const {
         return texture.width;
@@ -294,7 +289,7 @@
      */
     bool deferredUpdateScheduled;
     OpenGLRenderer* renderer;
-    RenderNode* displayList;
+    sp<RenderNode> displayList;
     Rect dirtyRect;
     bool debugDrawUpdate;
     bool hasDrawnSinceUpdate;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e1f484d..9dbcd36 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -537,7 +537,7 @@
 
 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
     if (layer->deferredUpdateScheduled && layer->renderer &&
-            layer->displayList && layer->displayList->isRenderable()) {
+            layer->displayList.get() && layer->displayList->isRenderable()) {
         ATRACE_CALL();
 
         Rect& dirty = layer->dirtyRect;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 663b67e..5010076 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -59,17 +59,6 @@
     delete mDisplayListData;
 }
 
-void RenderNode::destroyDisplayListDeferred(RenderNode* displayList) {
-    if (displayList) {
-        if (Caches::hasInstance()) {
-            DISPLAY_LIST_LOGD("Deferring display list destruction");
-            Caches::getInstance().deleteDisplayListDeferred(displayList);
-        } else {
-            delete displayList;
-        }
-    }
-}
-
 void RenderNode::setData(DisplayListData* data) {
     delete mDisplayListData;
     mDisplayListData = data;
@@ -104,8 +93,8 @@
     }
 
     if (mDisplayListData) {
-        for (size_t i = 0; i < mDisplayListData->children.size(); i++) {
-            RenderNode* childNode = mDisplayListData->children[i]->mDisplayList;
+        for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
+            RenderNode* childNode = mDisplayListData->children()[i]->mDisplayList;
             childNode->updateProperties();
         }
     }
@@ -118,8 +107,8 @@
         return true;
     }
 
-    for (size_t i = 0; i < mDisplayListData->children.size(); i++) {
-        RenderNode* childNode = mDisplayListData->children[i]->mDisplayList;
+    for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
+        RenderNode* childNode = mDisplayListData->children()[i]->mDisplayList;
         if (childNode->hasFunctors()) {
             return true;
         }
@@ -248,8 +237,8 @@
     // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
     // transform properties are applied correctly to top level children
     if (mDisplayListData == NULL) return;
-    for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
-        DrawDisplayListOp* childOp = mDisplayListData->children[i];
+    for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
+        DrawDisplayListOp* childOp = mDisplayListData->children()[i];
         childOp->mDisplayList->computeOrderingImpl(childOp,
                 &mProjectedNodes, &mat4::identity());
     }
@@ -277,11 +266,11 @@
         opState->mSkipInOrderDraw = false;
     }
 
-    if (mDisplayListData->children.size() > 0) {
+    if (mDisplayListData->children().size() > 0) {
         const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
         bool haveAppliedPropertiesToProjection = false;
-        for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
-            DrawDisplayListOp* childOp = mDisplayListData->children[i];
+        for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
+            DrawDisplayListOp* childOp = mDisplayListData->children()[i];
             RenderNode* child = childOp->mDisplayList;
 
             Vector<DrawDisplayListOp*>* projectionChildren = NULL;
@@ -375,10 +364,10 @@
 }
 
 void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) {
-    if (mDisplayListData == NULL || mDisplayListData->children.size() == 0) return;
+    if (mDisplayListData == NULL || mDisplayListData->children().size() == 0) return;
 
-    for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
-        DrawDisplayListOp* childOp = mDisplayListData->children[i];
+    for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
+        DrawDisplayListOp* childOp = mDisplayListData->children()[i];
         RenderNode* child = childOp->mDisplayList;
         float childZ = child->properties().getTranslationZ();
 
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index fb5336d..fd0fabc 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -41,6 +41,7 @@
 #include "DeferredDisplayList.h"
 #include "DisplayList.h"
 #include "RenderProperties.h"
+#include "utils/VirtualLightRefBase.h"
 
 class SkBitmap;
 class SkPaint;
@@ -76,7 +77,7 @@
  * recorded stream of canvas operations is refreshed. The DisplayList (and its properties) stay
  * attached.
  */
-class RenderNode {
+class RenderNode : public VirtualLightRefBase {
 public:
     ANDROID_API RenderNode();
     ANDROID_API ~RenderNode();
@@ -86,7 +87,6 @@
         kReplayFlag_ClipChildren = 0x1
     };
 
-    ANDROID_API static void destroyDisplayListDeferred(RenderNode* displayList);
     ANDROID_API static void outputLogBuffer(int fd);
 
     ANDROID_API void setData(DisplayListData* newData);
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 1e9089a..7b509a2 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -30,7 +30,19 @@
 namespace uirenderer {
 namespace renderthread {
 
-DrawFrameTask::DrawFrameTask() : mContext(0), mRenderNode(0) {
+SetDisplayListData::SetDisplayListData() : mNewData(0) {}
+
+SetDisplayListData::SetDisplayListData(RenderNode* node, DisplayListData* newData)
+        : mTargetNode(node), mNewData(newData) {
+}
+
+SetDisplayListData::~SetDisplayListData() {}
+
+void SetDisplayListData::apply() const {
+    mTargetNode->setData(mNewData);
+}
+
+DrawFrameTask::DrawFrameTask() : mContext(0), mTaskMode(MODE_INVALID), mRenderNode(0) {
 }
 
 DrawFrameTask::~DrawFrameTask() {
@@ -41,13 +53,15 @@
 }
 
 void DrawFrameTask::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) {
-    SetDisplayListData setter;
-    setter.targetNode = renderNode;
-    setter.newData = newData;
+    LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to setDisplayListData with!");
+
+    SetDisplayListData setter(renderNode, newData);
     mDisplayListDataUpdates.push(setter);
 }
 
 void DrawFrameTask::addLayer(DeferredLayerUpdater* layer) {
+    LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to addLayer with!");
+
     mLayers.push(layer);
 }
 
@@ -61,6 +75,8 @@
 }
 
 void DrawFrameTask::setRenderNode(RenderNode* renderNode) {
+    LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to setRenderNode with!");
+
     mRenderNode = renderNode;
 }
 
@@ -69,37 +85,55 @@
 }
 
 void DrawFrameTask::drawFrame(RenderThread* renderThread) {
-    LOG_ALWAYS_FATAL_IF(!mRenderNode, "Cannot drawFrame with no render node!");
+    LOG_ALWAYS_FATAL_IF(!mRenderNode.get(), "Cannot drawFrame with no render node!");
     LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
 
-    AutoMutex _lock(mLock);
-    renderThread->queue(this);
-    mSignal.wait(mLock);
+    postAndWait(renderThread, MODE_FULL);
 
     // Reset the single-frame data
     mDirty.setEmpty();
     mRenderNode = 0;
 }
 
+void DrawFrameTask::flushStateChanges(RenderThread* renderThread) {
+    LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
+
+    postAndWait(renderThread, MODE_STATE_ONLY);
+}
+
+void DrawFrameTask::postAndWait(RenderThread* renderThread, TaskMode mode) {
+    LOG_ALWAYS_FATAL_IF(mode == MODE_INVALID, "That's not a real mode, silly!");
+
+    mTaskMode = mode;
+    AutoMutex _lock(mLock);
+    renderThread->queue(this);
+    mSignal.wait(mLock);
+}
+
 void DrawFrameTask::run() {
     ATRACE_NAME("DrawFrame");
 
     syncFrameState();
 
+    if (mTaskMode == MODE_STATE_ONLY) {
+        unblockUiThread();
+        return;
+    }
+
     // Grab a copy of everything we need
     Rect dirtyCopy(mDirty);
-    RenderNode* renderNode = mRenderNode;
+    sp<RenderNode> renderNode = mRenderNode;
     CanvasContext* context = mContext;
 
     // This is temporary until WebView has a solution for syncing frame state
-    bool canUnblockUiThread = !requiresSynchronousDraw(renderNode);
+    bool canUnblockUiThread = !requiresSynchronousDraw(renderNode.get());
 
     // From this point on anything in "this" is *UNSAFE TO ACCESS*
     if (canUnblockUiThread) {
         unblockUiThread();
     }
 
-    drawRenderNode(context, renderNode, &dirtyCopy);
+    drawRenderNode(context, renderNode.get(), &dirtyCopy);
 
     if (!canUnblockUiThread) {
         unblockUiThread();
@@ -111,12 +145,16 @@
 
     for (size_t i = 0; i < mDisplayListDataUpdates.size(); i++) {
         const SetDisplayListData& setter = mDisplayListDataUpdates[i];
-        setter.targetNode->setData(setter.newData);
+        setter.apply();
     }
     mDisplayListDataUpdates.clear();
 
     mContext->processLayerUpdates(&mLayers);
-    mRenderNode->updateProperties();
+
+    // If we don't have an mRenderNode this is a state flush only
+    if (mRenderNode.get()) {
+        mRenderNode->updateProperties();
+    }
 }
 
 void DrawFrameTask::unblockUiThread() {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 5450dd5..4e9b244 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -18,6 +18,7 @@
 
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
 #include <utils/Vector.h>
 
 #include "RenderTask.h"
@@ -36,9 +37,16 @@
 class CanvasContext;
 class RenderThread;
 
-struct SetDisplayListData {
-    RenderNode* targetNode;
-    DisplayListData* newData;
+class SetDisplayListData {
+public:
+    // This ctor exists for Vector's usage
+    SetDisplayListData();
+    SetDisplayListData(RenderNode* node, DisplayListData* newData);
+    ~SetDisplayListData();
+    void apply() const;
+private:
+    sp<RenderNode> mTargetNode;
+    DisplayListData* mNewData;
 };
 
 /*
@@ -61,10 +69,18 @@
     void setRenderNode(RenderNode* renderNode);
     void setDirty(int left, int top, int right, int bottom);
     void drawFrame(RenderThread* renderThread);
+    void flushStateChanges(RenderThread* renderThread);
 
     virtual void run();
 
 private:
+    enum TaskMode {
+        MODE_INVALID,
+        MODE_FULL,
+        MODE_STATE_ONLY,
+    };
+
+    void postAndWait(RenderThread* renderThread, TaskMode mode);
     void syncFrameState();
     void unblockUiThread();
     static void drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty);
@@ -81,7 +97,8 @@
     /*********************************************
      *  Single frame data
      *********************************************/
-    RenderNode* mRenderNode;
+    TaskMode mTaskMode;
+    sp<RenderNode> mRenderNode;
     Rect mDirty;
     Vector<SetDisplayListData> mDisplayListDataUpdates;
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index cd711b0..43182d5 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -75,6 +75,9 @@
 
 void RenderProxy::destroyContext() {
     if (mContext) {
+        // Flush any pending changes to ensure all garbage is destroyed
+        mDrawFrameTask.flushStateChanges(&mRenderThread);
+
         SETUP_TASK(destroyContext);
         args->context = mContext;
         mContext = 0;
@@ -138,6 +141,10 @@
 }
 
 void RenderProxy::destroyCanvas() {
+    // If the canvas is being destroyed we won't be drawing again anytime soon
+    // So flush any pending state changes to allow for resource cleanup.
+    mDrawFrameTask.flushStateChanges(&mRenderThread);
+
     SETUP_TASK(destroyCanvas);
     args->context = mContext;
     post(task);
diff --git a/libs/hwui/utils/VirtualLightRefBase.h b/libs/hwui/utils/VirtualLightRefBase.h
new file mode 100644
index 0000000..b545aab
--- /dev/null
+++ b/libs/hwui/utils/VirtualLightRefBase.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef VIRTUALLIGHTREFBASE_H
+#define VIRTUALLIGHTREFBASE_H
+
+#include <utils/RefBase.h>
+
+namespace android {
+namespace uirenderer {
+
+// This is a wrapper around LightRefBase that simply enforces a virtual
+// destructor to eliminate the template requirement of LightRefBase
+class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
+public:
+    virtual ~VirtualLightRefBase() {}
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* VIRTUALLIGHTREFBASE_H */