Access VectorDrawableAtlas only on RenderThread
VectorDrawableAtlas dtor can run only on RenderThread, because
it releases GPU resources. It is usually CacheManager, which
destroys the atlas on RenderThread in response to trimMemory.
This CL fixes a rare situation, when a Java finalizer thread
deletes the atlas.
Bug: 137722646
Test: Manual testing on a device
Change-Id: I9d900809c23efaead9aaf16ee3306bc8c7c6b379
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index f91d178..61403aa 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -16,19 +16,24 @@
#include "VectorDrawable.h"
+#include <math.h>
+#include <string.h>
#include <utils/Log.h>
-#include "hwui/Paint.h"
+
#include "PathParser.h"
#include "SkColorFilter.h"
#include "SkImageInfo.h"
#include "SkShader.h"
+#include "hwui/Paint.h"
+
+#ifdef __ANDROID__
+#include "renderthread/RenderThread.h"
+#endif
+
#include "utils/Macros.h"
#include "utils/TraceUtils.h"
#include "utils/VectorDrawableUtils.h"
-#include <math.h>
-#include <string.h>
-
namespace android {
namespace uirenderer {
namespace VectorDrawable {
@@ -472,7 +477,7 @@
mStagingProperties.getBounds().bottom(), &paint);
}
-void Tree::getPaintFor(SkPaint* outPaint, const TreeProperties &prop) const {
+void Tree::getPaintFor(SkPaint* outPaint, const TreeProperties& prop) const {
// HWUI always draws VD with bilinear filtering.
outPaint->setFilterQuality(kLow_SkFilterQuality);
if (prop.getColorFilter() != nullptr) {
@@ -492,7 +497,7 @@
}
void Tree::updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context) {
-#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
SkRect dst;
sk_sp<SkSurface> surface = mCache.getSurface(&dst);
bool canReuseSurface = surface && dst.width() >= mProperties.getScaledWidth() &&
@@ -533,7 +538,7 @@
sk_sp<SkSurface> Tree::Cache::getSurface(SkRect* bounds) {
sk_sp<SkSurface> surface;
-#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
sp<skiapipeline::VectorDrawableAtlas> atlas = mAtlas.promote();
if (atlas.get() && mAtlasKey != INVALID_ATLAS_KEY) {
auto atlasEntry = atlas->getEntry(mAtlasKey);
@@ -547,13 +552,28 @@
}
void Tree::Cache::clear() {
-#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
- sp<skiapipeline::VectorDrawableAtlas> lockAtlas = mAtlas.promote();
- if (lockAtlas.get()) {
- lockAtlas->releaseEntry(mAtlasKey);
+#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+ if (mAtlasKey != INVALID_ATLAS_KEY) {
+ if (renderthread::RenderThread::isCurrent()) {
+ sp<skiapipeline::VectorDrawableAtlas> lockAtlas = mAtlas.promote();
+ if (lockAtlas.get()) {
+ lockAtlas->releaseEntry(mAtlasKey);
+ }
+ } else {
+ // VectorDrawableAtlas can be accessed only on RenderThread.
+ // Use by-copy capture of the current Cache variables, because "this" may not be valid
+ // by the time the lambda is evaluated on RenderThread.
+ renderthread::RenderThread::getInstance().queue().post(
+ [atlas = mAtlas, atlasKey = mAtlasKey]() {
+ sp<skiapipeline::VectorDrawableAtlas> lockAtlas = atlas.promote();
+ if (lockAtlas.get()) {
+ lockAtlas->releaseEntry(atlasKey);
+ }
+ });
+ }
+ mAtlasKey = INVALID_ATLAS_KEY;
}
mAtlas = nullptr;
- mAtlasKey = INVALID_ATLAS_KEY;
#endif
}
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index df7eeb3..5aa1af3 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -53,6 +53,10 @@
class VkFunctorDrawHandler;
}
+namespace VectorDrawable {
+class Tree;
+}
+
namespace renderthread {
class CanvasContext;
@@ -138,6 +142,7 @@
friend class android::uirenderer::TestUtils;
friend class android::uirenderer::WebViewFunctor;
friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
+ friend class android::uirenderer::VectorDrawable::Tree;
RenderThread();
virtual ~RenderThread();