Fix crash in "Tree::updateBitmapCache"
Fix crash caused by updating vectordrawable cache for objects
from previous frames, which may have been deleted.
Bug: 67940327
Test: Ran CtsUiRenderingTestCases test
Change-Id: I4466235e78e9b7937a0d4428240574d9e3d0989f
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index c4bd1e1..cdf4aee 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -75,6 +75,12 @@
mPinnedImages.clear();
}
+void SkiaPipeline::onPrepareTree() {
+ // The only time mVectorDrawables is not empty is if prepare tree was called 2 times without
+ // a renderFrame in the middle.
+ mVectorDrawables.clear();
+}
+
void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo) {
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 3e6ae30..dc0b8f6d 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -37,6 +37,7 @@
bool pinImages(std::vector<SkImage*>& mutableImages) override;
bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override { return false; }
void unpinImages() override;
+ void onPrepareTree() override;
void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5d7f594..ad684db 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -331,6 +331,7 @@
info.layerUpdateQueue = &mLayerUpdateQueue;
mAnimationContext->startFrame(info.mode);
+ mRenderPipeline->onPrepareTree();
for (const sp<RenderNode>& node : mRenderNodes) {
// Only the primary target node will be drawn full - all other nodes would get drawn in
// real time mode. In case of a window, the primary node is the window content and the other
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index f9b6e384..0bb3889 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -81,6 +81,7 @@
virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
virtual void unpinImages() = 0;
+ virtual void onPrepareTree() = 0;
virtual ~IRenderPipeline() {}
};
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index 4ca19fb..1f467c1 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -58,6 +58,7 @@
bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; }
bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override;
void unpinImages() override;
+ void onPrepareTree() override {}
static void destroyLayer(RenderNode* node);
static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap);
static void invokeFunctor(const RenderThread& thread, Functor* functor);
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index b397b15..f430ce6 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -56,6 +56,40 @@
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
}
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) {
+
+ auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
+ [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+ redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
+
+ LayerUpdateQueue layerUpdateQueue;
+ SkRect dirty = SkRect::MakeLargest();
+ std::vector<sp<RenderNode>> renderNodes;
+ renderNodes.push_back(redNode);
+ bool opaque = true;
+ android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
+ auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+ {
+ //add a pointer to a deleted vector drawable object in the pipeline
+ sp<VectorDrawableRoot> dirtyVD(new VectorDrawableRoot(new VectorDrawable::Group()));
+ dirtyVD->mutateProperties()->setScaledSize(5,5);
+ pipeline->getVectorDrawables()->push_back(dirtyVD.get());
+ }
+
+ //pipeline should clean list of dirty vector drawables before prepare tree
+ pipeline->onPrepareTree();
+
+ auto surface = SkSurface::MakeRasterN32Premul(1, 1);
+ surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+
+ //drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
+ opaque, false, contentDrawBounds, surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
+}
+
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
auto halfGreenNode = TestUtils::createSkiaNode(0, 0, 2, 2,
[](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {