Convert DisplayList to a value-type wrapper

Make DisplayList its own type instead of an alias,
pushing the Skia aspect behind it mostly. Removes a bunch
of manual memory management and opens the door to DisplayList
being a union type with multiple implementations

Test: builds (somehow), boots, hwuiunit passes, CtsUiRendering passes
Change-Id: I1d7806aa3afc5d9ece08b06959920078a5814c59
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index dc63e5d..3aa5b4b 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -18,6 +18,8 @@
 
 #include "pipeline/skia/SkiaDisplayList.h"
 
+#include <memory>
+
 namespace android {
 namespace uirenderer {
 
@@ -29,7 +31,119 @@
 /**
  * Data structure that holds the list of commands used in display list stream
  */
-using DisplayList = skiapipeline::SkiaDisplayList;
+//using DisplayList = skiapipeline::SkiaDisplayList;
+class DisplayList {
+public:
+    // Constructs an empty (invalid) DisplayList
+    explicit DisplayList() {}
+
+    // Constructs a DisplayList from a SkiaDisplayList
+    explicit DisplayList(std::unique_ptr<skiapipeline::SkiaDisplayList> impl)
+        : mImpl(std::move(impl)) {}
+
+    // Move support
+    DisplayList(DisplayList&& other) : mImpl(std::move(other.mImpl)) {}
+    DisplayList& operator=(DisplayList&& other) {
+        mImpl = std::move(other.mImpl);
+        return *this;
+    }
+
+    // No copy support
+    DisplayList(const DisplayList& other) = delete;
+    DisplayList& operator=(const DisplayList&) = delete;
+
+    void updateChildren(std::function<void(RenderNode*)> updateFn) {
+        mImpl->updateChildren(std::move(updateFn));
+    }
+
+    [[nodiscard]] explicit operator bool() const {
+        return mImpl.get() != nullptr;
+    }
+
+    // If true this DisplayList contains a backing content, even if that content is empty
+    // If false, there this DisplayList is in an "empty" state
+    [[nodiscard]] bool isValid() const {
+        return mImpl.get() != nullptr;
+    }
+
+    [[nodiscard]] bool isEmpty() const {
+        return !hasContent();
+    }
+
+    [[nodiscard]] bool hasContent() const {
+        return mImpl && !(mImpl->isEmpty());
+    }
+
+    [[nodiscard]] bool containsProjectionReceiver() const {
+        return mImpl && mImpl->containsProjectionReceiver();
+    }
+
+    [[nodiscard]] skiapipeline::SkiaDisplayList* asSkiaDl() {
+        return mImpl.get();
+    }
+
+    [[nodiscard]] const skiapipeline::SkiaDisplayList* asSkiaDl() const {
+        return mImpl.get();
+    }
+
+    [[nodiscard]] bool hasVectorDrawables() const {
+        return mImpl && mImpl->hasVectorDrawables();
+    }
+
+    void clear(RenderNode* owningNode = nullptr) {
+        if (mImpl && owningNode && mImpl->reuseDisplayList(owningNode)) {
+            // TODO: This is a bit sketchy to have a unique_ptr temporarily owned twice
+            // Do something to cleanup reuseDisplayList passing itself to the RenderNode
+            mImpl.release();
+        } else {
+            mImpl = nullptr;
+        }
+    }
+
+    [[nodiscard]] size_t getUsedSize() const {
+        return mImpl ? mImpl->getUsedSize() : 0;
+    }
+
+    [[nodiscard]] size_t getAllocatedSize() const {
+        return mImpl ? mImpl->getAllocatedSize() : 0;
+    }
+
+    void output(std::ostream& output, uint32_t level) const {
+        if (mImpl) {
+            mImpl->output(output, level);
+        }
+    }
+
+    [[nodiscard]] bool hasFunctor() const {
+        return mImpl && mImpl->hasFunctor();
+    }
+
+    bool prepareListAndChildren(
+            TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+            std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
+        return mImpl && mImpl->prepareListAndChildren(
+                observer, info, functorsNeedLayer, std::move(childFn));
+    }
+
+    void syncContents(const WebViewSyncData& data) {
+        if (mImpl) {
+            mImpl->syncContents(data);
+        }
+    }
+
+    [[nodiscard]] bool hasText() const {
+        return mImpl && mImpl->hasText();
+    }
+
+    void applyColorTransform(ColorTransform transform) {
+        if (mImpl) {
+            mImpl->mDisplayList.applyColorTransform(transform);
+        }
+    }
+
+private:
+    std::unique_ptr<skiapipeline::SkiaDisplayList> mImpl;
+};
 
 }  // namespace uirenderer
 }  // namespace android
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index c4189da..a6a7b12 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -28,7 +28,6 @@
 #include "SkPaint.h"
 #include "SkPath.h"
 #include "SkRect.h"
-#include "SkTemplates.h"
 
 #include <vector>
 
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 1c78eed..44f54ee 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -70,19 +70,17 @@
 RenderNode::~RenderNode() {
     ImmediateRemoved observer(nullptr);
     deleteDisplayList(observer);
-    delete mStagingDisplayList;
     LOG_ALWAYS_FATAL_IF(hasLayer(), "layer missed detachment!");
 }
 
-void RenderNode::setStagingDisplayList(DisplayList* displayList) {
-    mValid = (displayList != nullptr);
+void RenderNode::setStagingDisplayList(DisplayList&& newData) {
+    mValid = newData.isValid();
     mNeedsDisplayListSync = true;
-    delete mStagingDisplayList;
-    mStagingDisplayList = displayList;
+    mStagingDisplayList = std::move(newData);
 }
 
 void RenderNode::discardStagingDisplayList() {
-    setStagingDisplayList(nullptr);
+    setStagingDisplayList(DisplayList());
 }
 
 /**
@@ -105,32 +103,22 @@
 
     properties().debugOutputProperties(output, level + 1);
 
-    if (mDisplayList) {
-        mDisplayList->output(output, level);
-    }
+    mDisplayList.output(output, level);
     output << std::string(level * 2, ' ') << "/RenderNode(" << getName() << " " << this << ")";
     output << std::endl;
 }
 
 int RenderNode::getUsageSize() {
     int size = sizeof(RenderNode);
-    if (mStagingDisplayList) {
-        size += mStagingDisplayList->getUsedSize();
-    }
-    if (mDisplayList && mDisplayList != mStagingDisplayList) {
-        size += mDisplayList->getUsedSize();
-    }
+    size += mStagingDisplayList.getUsedSize();
+    size += mDisplayList.getUsedSize();
     return size;
 }
 
 int RenderNode::getAllocatedSize() {
     int size = sizeof(RenderNode);
-    if (mStagingDisplayList) {
-        size += mStagingDisplayList->getAllocatedSize();
-    }
-    if (mDisplayList && mDisplayList != mStagingDisplayList) {
-        size += mDisplayList->getAllocatedSize();
-    }
+    size += mStagingDisplayList.getAllocatedSize();
+    size += mDisplayList.getAllocatedSize();
     return size;
 }
 
@@ -246,9 +234,9 @@
 
     bool willHaveFunctor = false;
     if (info.mode == TreeInfo::MODE_FULL && mStagingDisplayList) {
-        willHaveFunctor = mStagingDisplayList->hasFunctor();
+        willHaveFunctor = mStagingDisplayList.hasFunctor();
     } else if (mDisplayList) {
-        willHaveFunctor = mDisplayList->hasFunctor();
+        willHaveFunctor = mDisplayList.hasFunctor();
     }
     bool childFunctorsNeedLayer =
             mProperties.prepareForFunctorPresence(willHaveFunctor, functorsNeedLayer);
@@ -263,8 +251,8 @@
     }
 
     if (mDisplayList) {
-        info.out.hasFunctors |= mDisplayList->hasFunctor();
-        bool isDirty = mDisplayList->prepareListAndChildren(
+        info.out.hasFunctors |= mDisplayList.hasFunctor();
+        bool isDirty = mDisplayList.prepareListAndChildren(
                 observer, info, childFunctorsNeedLayer,
                 [](RenderNode* child, TreeObserver& observer, TreeInfo& info,
                    bool functorsNeedLayer) {
@@ -318,16 +306,15 @@
     // Make sure we inc first so that we don't fluctuate between 0 and 1,
     // which would thrash the layer cache
     if (mStagingDisplayList) {
-        mStagingDisplayList->updateChildren([](RenderNode* child) { child->incParentRefCount(); });
+        mStagingDisplayList.updateChildren([](RenderNode* child) { child->incParentRefCount(); });
     }
     deleteDisplayList(observer, info);
-    mDisplayList = mStagingDisplayList;
-    mStagingDisplayList = nullptr;
+    mDisplayList = std::move(mStagingDisplayList);
     if (mDisplayList) {
         WebViewSyncData syncData {
             .applyForceDark = info && !info->disableForceDark
         };
-        mDisplayList->syncContents(syncData);
+        mDisplayList.syncContents(syncData);
         handleForceDark(info);
     }
 }
@@ -337,15 +324,18 @@
         return;
     }
     auto usage = usageHint();
-    const auto& children = mDisplayList->mChildNodes;
-    if (mDisplayList->hasText()) {
+    FatVector<RenderNode*, 6> children;
+    mDisplayList.updateChildren([&children](RenderNode* node) {
+        children.push_back(node);
+    });
+    if (mDisplayList.hasText()) {
         usage = UsageHint::Foreground;
     }
     if (usage == UsageHint::Unknown) {
         if (children.size() > 1) {
             usage = UsageHint::Background;
         } else if (children.size() == 1 &&
-                children.front().getRenderNode()->usageHint() !=
+                children.front()->usageHint() !=
                         UsageHint::Background) {
             usage = UsageHint::Background;
         }
@@ -354,7 +344,7 @@
         // Crude overlap check
         SkRect drawn = SkRect::MakeEmpty();
         for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
-            const auto& child = iter->getRenderNode();
+            const auto& child = *iter;
             // We use stagingProperties here because we haven't yet sync'd the children
             SkRect bounds = SkRect::MakeXYWH(child->stagingProperties().getX(), child->stagingProperties().getY(),
                     child->stagingProperties().getWidth(), child->stagingProperties().getHeight());
@@ -365,7 +355,7 @@
             drawn.join(bounds);
         }
     }
-    mDisplayList->mDisplayList.applyColorTransform(
+    mDisplayList.applyColorTransform(
             usage == UsageHint::Background ? ColorTransform::Dark : ColorTransform::Light);
 }
 
@@ -382,20 +372,17 @@
 
 void RenderNode::deleteDisplayList(TreeObserver& observer, TreeInfo* info) {
     if (mDisplayList) {
-        mDisplayList->updateChildren(
+        mDisplayList.updateChildren(
                 [&observer, info](RenderNode* child) { child->decParentRefCount(observer, info); });
-        if (!mDisplayList->reuseDisplayList(this)) {
-            delete mDisplayList;
-        }
+        mDisplayList.clear(this);
     }
-    mDisplayList = nullptr;
 }
 
 void RenderNode::destroyHardwareResources(TreeInfo* info) {
     if (hasLayer()) {
         this->setLayerSurface(nullptr);
     }
-    setStagingDisplayList(nullptr);
+    discardStagingDisplayList();
 
     ImmediateRemoved observer(info);
     deleteDisplayList(observer, info);
@@ -406,7 +393,7 @@
         this->setLayerSurface(nullptr);
     }
     if (mDisplayList) {
-        mDisplayList->updateChildren([](RenderNode* child) { child->destroyLayers(); });
+        mDisplayList.updateChildren([](RenderNode* child) { child->destroyLayers(); });
     }
 }
 
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 1eaf0d4..39ea53b 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -100,17 +100,17 @@
     // See flags defined in DisplayList.java
     enum ReplayFlag { kReplayFlag_ClipChildren = 0x1 };
 
-    void setStagingDisplayList(DisplayList* newData);
+    void setStagingDisplayList(DisplayList&& newData);
     void discardStagingDisplayList();
 
     void output();
     int getUsageSize();
     int getAllocatedSize();
 
-    bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); }
+    bool isRenderable() const { return mDisplayList.hasContent(); }
 
     bool hasProjectionReceiver() const {
-        return mDisplayList && mDisplayList->containsProjectionReceiver();
+        return mDisplayList.containsProjectionReceiver();
     }
 
     const char* getName() const { return mName.string(); }
@@ -169,12 +169,14 @@
 
     bool nothingToDraw() const {
         const Outline& outline = properties().getOutline();
-        return mDisplayList == nullptr || properties().getAlpha() <= 0 ||
+        return !mDisplayList.isValid() || properties().getAlpha() <= 0 ||
                (outline.getShouldClip() && outline.isEmpty()) || properties().getScaleX() == 0 ||
                properties().getScaleY() == 0;
     }
 
-    const DisplayList* getDisplayList() const { return mDisplayList; }
+    const DisplayList& getDisplayList() const { return mDisplayList; }
+    // TODO: can this be cleaned up?
+    DisplayList& getDisplayList() { return mDisplayList; }
 
     // Note: The position callbacks are relying on the listener using
     // the frameNumber to appropriately batch/synchronize these transactions.
@@ -253,8 +255,8 @@
 
     bool mNeedsDisplayListSync;
     // WARNING: Do not delete this directly, you must go through deleteDisplayList()!
-    DisplayList* mDisplayList;
-    DisplayList* mStagingDisplayList;
+    DisplayList mDisplayList;
+    DisplayList mStagingDisplayList;
 
     int64_t mDamageGenerationId;
 
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 584321e..6161ddf 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -53,9 +53,9 @@
         LOG_ALWAYS_FATAL("SkiaCanvas cannot be reset as a recording canvas");
     }
 
-    virtual uirenderer::DisplayList* finishRecording() override {
+    virtual uirenderer::DisplayList finishRecording() override {
         LOG_ALWAYS_FATAL("SkiaCanvas does not produce a DisplayList");
-        return nullptr;
+        return uirenderer::DisplayList();
     }
     virtual void enableZ(bool enableZ) override {
         LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ");
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 11fa322..b4bfd26 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -117,7 +117,7 @@
 
     virtual void resetRecording(int width, int height,
                                 uirenderer::RenderNode* renderNode = nullptr) = 0;
-    virtual uirenderer::DisplayList* finishRecording() = 0;
+    [[nodiscard]] virtual uirenderer::DisplayList finishRecording() = 0;
     virtual void enableZ(bool enableZ) = 0;
 
     bool isHighContrastText() const { return uirenderer::Properties::enableHighContrastText; }
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index eb9885a..05278f2 100755
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -3,11 +3,12 @@
 #include "Bitmap.h"
 
 #include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkColorSpace.h"
 #include "SkPixelRef.h"
 #include "SkImageEncoder.h"
 #include "SkImageInfo.h"
-#include "SkColor.h"
-#include "SkColorSpace.h"
 #include "GraphicsJNI.h"
 #include "SkStream.h"
 #include "SkWebpEncoder.h"
diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp
index 52522a3..cf02051 100644
--- a/libs/hwui/jni/BitmapFactory.cpp
+++ b/libs/hwui/jni/BitmapFactory.cpp
@@ -8,9 +8,11 @@
 #include "MimeType.h"
 #include "NinePatchPeeker.h"
 #include "SkAndroidCodec.h"
+#include "SkCanvas.h"
 #include "SkMath.h"
 #include "SkPixelRef.h"
 #include "SkStream.h"
+#include "SkString.h"
 #include "SkUtils.h"
 #include "Utils.h"
 
diff --git a/libs/hwui/jni/GraphicsJNI.h b/libs/hwui/jni/GraphicsJNI.h
index 541d5a5..ba407f2 100644
--- a/libs/hwui/jni/GraphicsJNI.h
+++ b/libs/hwui/jni/GraphicsJNI.h
@@ -24,6 +24,7 @@
 namespace skia {
     class BitmapRegionDecoder;
 }
+class Canvas;
 class Paint;
 struct Typeface;
 }
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index 26ff8bf..3580bed 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -29,7 +29,7 @@
  */
 class DumpOpsCanvas : public SkCanvas {
 public:
-    DumpOpsCanvas(std::ostream& output, int level, SkiaDisplayList& displayList)
+    DumpOpsCanvas(std::ostream& output, int level, const SkiaDisplayList& displayList)
             : mOutput(output)
             , mLevel(level)
             , mDisplayList(displayList)
@@ -127,7 +127,7 @@
     }
 
 private:
-    RenderNodeDrawable* getRenderNodeDrawable(SkDrawable* drawable) {
+    const RenderNodeDrawable* getRenderNodeDrawable(SkDrawable* drawable) {
         for (auto& child : mDisplayList.mChildNodes) {
             if (drawable == &child) {
                 return &child;
@@ -147,7 +147,7 @@
 
     std::ostream& mOutput;
     int mLevel;
-    SkiaDisplayList& mDisplayList;
+    const SkiaDisplayList& mDisplayList;
     std::string mIdent;
 };
 
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 1473b3e..070a765 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -61,12 +61,11 @@
             SkAutoCanvasRestore acr(canvas, true);
             SkMatrix nodeMatrix;
             mat4 hwuiMatrix(child.getRecordedMatrix());
-            auto childNode = child.getRenderNode();
+            const RenderNode* childNode = child.getRenderNode();
             childNode->applyViewPropertyTransforms(hwuiMatrix);
             hwuiMatrix.copyTo(nodeMatrix);
             canvas->concat(nodeMatrix);
-            SkiaDisplayList* childDisplayList = static_cast<SkiaDisplayList*>(
-                    (const_cast<DisplayList*>(childNode->getDisplayList())));
+            const SkiaDisplayList* childDisplayList = childNode->getDisplayList().asSkiaDl();
             if (childDisplayList) {
                 drawBackwardsProjectedNodes(canvas, *childDisplayList, nestLevel + 1);
             }
@@ -144,7 +143,7 @@
         return;
     }
 
-    SkiaDisplayList* displayList = (SkiaDisplayList*)renderNode->getDisplayList();
+    SkiaDisplayList* displayList = renderNode->getDisplayList().asSkiaDl();
 
     SkAutoCanvasRestore acr(canvas, true);
     const RenderProperties& properties = this->getNodeProperties();
@@ -213,14 +212,14 @@
     if (mComposeLayer) {
         setViewProperties(properties, canvas, &alphaMultiplier);
     }
-    SkiaDisplayList* displayList = (SkiaDisplayList*)mRenderNode->getDisplayList();
+    SkiaDisplayList* displayList = mRenderNode->getDisplayList().asSkiaDl();
     displayList->mParentMatrix = canvas->getTotalMatrix();
 
     // TODO should we let the bound of the drawable do this for us?
     const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
     bool quickRejected = properties.getClipToBounds() && canvas->quickReject(bounds);
     if (!quickRejected) {
-        SkiaDisplayList* displayList = (SkiaDisplayList*)renderNode->getDisplayList();
+        SkiaDisplayList* displayList = renderNode->getDisplayList().asSkiaDl();
         const LayerProperties& layerProperties = properties.layerProperties();
         // composing a hardware layer
         if (renderNode->getLayerSurface() && mComposeLayer) {
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index c63f5d3..e6c6e10 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -172,7 +172,7 @@
     new (&allocator) LinearAllocator();
 }
 
-void SkiaDisplayList::output(std::ostream& output, uint32_t level) {
+void SkiaDisplayList::output(std::ostream& output, uint32_t level) const {
     DumpOpsCanvas canvas(output, level, *this);
     mDisplayList.draw(&canvas);
 }
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index f2f19ba..483264f 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -142,7 +142,7 @@
 
     void draw(SkCanvas* canvas) { mDisplayList.draw(canvas); }
 
-    void output(std::ostream& output, uint32_t level);
+    void output(std::ostream& output, uint32_t level) const;
 
     LinearAllocator allocator;
 
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 6e7493c..d14dc36 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -98,7 +98,7 @@
             continue;
         }
         SkASSERT(layerNode->getLayerSurface());
-        SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList();
+        SkiaDisplayList* displayList = layerNode->getDisplayList().asSkiaDl();
         if (!displayList || displayList->isEmpty()) {
             ALOGE("%p drawLayers(%s) : missing drawable", layerNode, layerNode->getName());
             return;
@@ -288,7 +288,7 @@
 
 // recurse through the rendernode's children, add any nodes which are layers to the queue.
 static void collectLayers(RenderNode* node, LayerUpdateQueue* layers) {
-    SkiaDisplayList* dl = (SkiaDisplayList*)node->getDisplayList();
+    SkiaDisplayList* dl = node->getDisplayList().asSkiaDl();
     if (dl) {
         const auto& prop = node->properties();
         if (node->hasLayer()) {
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index a436278..f460783 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -55,11 +55,11 @@
     SkiaCanvas::reset(&mRecorder);
 }
 
-uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() {
+uirenderer::DisplayList SkiaRecordingCanvas::finishRecording() {
     // close any existing chunks if necessary
     enableZ(false);
     mRecorder.restoreToCount(1);
-    return mDisplayList.release();
+    return uirenderer::DisplayList(std::move(mDisplayList));
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 83e9349..cbad467 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -43,7 +43,7 @@
         initDisplayList(renderNode, width, height);
     }
 
-    virtual uirenderer::DisplayList* finishRecording() override;
+    virtual uirenderer::DisplayList finishRecording() override;
 
     virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) override;
     virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) override;
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index c1d8b76..81cc6a9 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -212,7 +212,8 @@
             int left, int top, int right, int bottom,
             std::function<void(RenderProperties& props, skiapipeline::SkiaRecordingCanvas& canvas)>
                     setup,
-            const char* name = nullptr, skiapipeline::SkiaDisplayList* displayList = nullptr) {
+            const char* name = nullptr,
+            std::unique_ptr<skiapipeline::SkiaDisplayList> displayList = nullptr) {
         sp<RenderNode> node = new RenderNode();
         if (name) {
             node->setName(name);
@@ -220,7 +221,7 @@
         RenderProperties& props = node->mutateStagingProperties();
         props.setLeftTopRightBottom(left, top, right, bottom);
         if (displayList) {
-            node->setStagingDisplayList(displayList);
+            node->setStagingDisplayList(DisplayList(std::move(displayList)));
         }
         if (setup) {
             std::unique_ptr<skiapipeline::SkiaRecordingCanvas> canvas(
@@ -348,13 +349,11 @@
             node->mNeedsDisplayListSync = false;
             node->syncDisplayList(observer, nullptr);
         }
-        auto displayList = node->getDisplayList();
+        auto& displayList = node->getDisplayList();
         if (displayList) {
-            for (auto&& childDr :
-                 static_cast<skiapipeline::SkiaDisplayList*>(const_cast<DisplayList*>(displayList))
-                         ->mChildNodes) {
-                syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode());
-            }
+            displayList.updateChildren([](RenderNode* child) {
+                syncHierarchyPropertiesAndDisplayListImpl(child);
+            });
         }
     }
 
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index d393c69..ade1ddd 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -45,19 +45,19 @@
 
 void BM_DisplayListCanvas_record_empty(benchmark::State& benchState) {
     std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
-    delete canvas->finishRecording();
+    static_cast<void>(canvas->finishRecording());
 
     while (benchState.KeepRunning()) {
         canvas->resetRecording(100, 100);
         benchmark::DoNotOptimize(canvas.get());
-        delete canvas->finishRecording();
+        static_cast<void>(canvas->finishRecording());
     }
 }
 BENCHMARK(BM_DisplayListCanvas_record_empty);
 
 void BM_DisplayListCanvas_record_saverestore(benchmark::State& benchState) {
     std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
-    delete canvas->finishRecording();
+    static_cast<void>(canvas->finishRecording());
 
     while (benchState.KeepRunning()) {
         canvas->resetRecording(100, 100);
@@ -66,20 +66,20 @@
         benchmark::DoNotOptimize(canvas.get());
         canvas->restore();
         canvas->restore();
-        delete canvas->finishRecording();
+        static_cast<void>(canvas->finishRecording());
     }
 }
 BENCHMARK(BM_DisplayListCanvas_record_saverestore);
 
 void BM_DisplayListCanvas_record_translate(benchmark::State& benchState) {
     std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
-    delete canvas->finishRecording();
+    static_cast<void>(canvas->finishRecording());
 
     while (benchState.KeepRunning()) {
         canvas->resetRecording(100, 100);
         canvas->scale(10, 10);
         benchmark::DoNotOptimize(canvas.get());
-        delete canvas->finishRecording();
+        static_cast<void>(canvas->finishRecording());
     }
 }
 BENCHMARK(BM_DisplayListCanvas_record_translate);
@@ -92,7 +92,7 @@
  */
 void BM_DisplayListCanvas_record_simpleBitmapView(benchmark::State& benchState) {
     std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
-    delete canvas->finishRecording();
+    static_cast<void>(canvas->finishRecording());
 
     Paint rectPaint;
     sk_sp<Bitmap> iconBitmap(TestUtils::createBitmap(80, 80));
@@ -111,7 +111,7 @@
             canvas->restore();
         }
         benchmark::DoNotOptimize(canvas.get());
-        delete canvas->finishRecording();
+        static_cast<void>(canvas->finishRecording());
     }
 }
 BENCHMARK(BM_DisplayListCanvas_record_simpleBitmapView);
@@ -122,7 +122,7 @@
     });
 
     std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
-    delete canvas->finishRecording();
+    static_cast<void>(canvas->finishRecording());
 
     while (benchState.KeepRunning()) {
         canvas->resetRecording(200, 200);
@@ -143,7 +143,7 @@
         canvas->enableZ(false);
         canvas->restoreToCount(clipRestoreCount);
 
-        delete canvas->finishRecording();
+        static_cast<void>(canvas->finishRecording());
     }
 }
 BENCHMARK(BM_DisplayListCanvas_basicViewGroupDraw)->Arg(1)->Arg(5)->Arg(10);
diff --git a/libs/hwui/tests/microbench/RenderNodeBench.cpp b/libs/hwui/tests/microbench/RenderNodeBench.cpp
index 618988f..dd3f737 100644
--- a/libs/hwui/tests/microbench/RenderNodeBench.cpp
+++ b/libs/hwui/tests/microbench/RenderNodeBench.cpp
@@ -35,7 +35,7 @@
 void BM_RenderNode_recordSimple(benchmark::State& state) {
     sp<RenderNode> node = new RenderNode();
     std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
-    delete canvas->finishRecording();
+    static_cast<void>(canvas->finishRecording());
 
     while (state.KeepRunning()) {
         canvas->resetRecording(100, 100, node.get());
@@ -48,12 +48,12 @@
 void BM_RenderNode_recordSimpleWithReuse(benchmark::State& state) {
     sp<RenderNode> node = new RenderNode();
     std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(100, 100));
-    delete canvas->finishRecording();
+    static_cast<void>(canvas->finishRecording());
 
     while (state.KeepRunning()) {
         canvas->resetRecording(100, 100, node.get());
         canvas->drawColor(0x00000000, SkBlendMode::kSrcOver);
-        canvas->finishRecording()->reuseDisplayList(node.get());
+        canvas->finishRecording().clear(node.get());
     }
 }
 BENCHMARK(BM_RenderNode_recordSimpleWithReuse);
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index 4659a92..61bd646 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -326,7 +326,7 @@
 
     // Check that the VD is in the dislay list, and the layer update queue contains the correct
     // damage rect.
-    EXPECT_TRUE(rootNode->getDisplayList()->hasVectorDrawables());
+    EXPECT_TRUE(rootNode->getDisplayList().hasVectorDrawables());
     ASSERT_FALSE(info.layerUpdateQueue->entries().empty());
     EXPECT_EQ(rootNode.get(), info.layerUpdateQueue->entries().at(0).renderNode.get());
     EXPECT_EQ(uirenderer::Rect(0, 0, 200, 400), info.layerUpdateQueue->entries().at(0).damage);
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index c63f008..801a294 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -38,12 +38,13 @@
 }
 
 TEST(SkiaDisplayList, reset) {
-    std::unique_ptr<SkiaDisplayList> skiaDL;
+    DisplayList displayList;
     {
         SkiaRecordingCanvas canvas{nullptr, 1, 1};
         canvas.drawColor(0, SkBlendMode::kSrc);
-        skiaDL.reset(canvas.finishRecording());
+        displayList = canvas.finishRecording();
     }
+    SkiaDisplayList* skiaDL = displayList.asSkiaDl();
 
     SkCanvas dummyCanvas;
     RenderNodeDrawable drawable(nullptr, &dummyCanvas);