Release VectorDrawable cache surface on render thread

Release VectorDrawable cache surface on render thread.
This is fixing an assert in skia GrSingleOwner.h:33.

Test: Ran gmail before and after the change.
Bug: 64842607
Change-Id: I46e0c2557ac5b2fc3be2cc2d35abf96f6d6c9399
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
index 437653a..2396990 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
@@ -21,6 +21,7 @@
 #include <cmath>
 #include "utils/TraceUtils.h"
 #include "renderthread/RenderProxy.h"
+#include "renderthread/RenderThread.h"
 
 namespace android {
 namespace uirenderer {
@@ -228,6 +229,15 @@
 
 void VectorDrawableAtlas::releaseEntry(AtlasKey atlasKey) {
     if (INVALID_ATLAS_KEY != atlasKey) {
+        if (!renderthread::RenderThread::isCurrent()) {
+            {
+                AutoMutex _lock(mReleaseKeyLock);
+                mKeysForRelease.push_back(atlasKey);
+            }
+            // invoke releaseEntry on the renderthread
+            renderthread::RenderProxy::releaseVDAtlasEntries();
+            return;
+        }
         CacheEntry* entry = reinterpret_cast<CacheEntry*>(atlasKey);
         if (!entry->surface) {
             // Store freed atlas rectangles in "mFreeRects" and try to reuse them later, when atlas
@@ -245,6 +255,14 @@
     }
 }
 
+void VectorDrawableAtlas::delayedReleaseEntries() {
+    AutoMutex _lock(mReleaseKeyLock);
+    for (auto key : mKeysForRelease) {
+        releaseEntry(key);
+    }
+    mKeysForRelease.clear();
+}
+
 sk_sp<SkSurface> VectorDrawableAtlas::createSurface(int width, int height, GrContext* context) {
 #ifndef ANDROID_ENABLE_LINEAR_BLENDING
     sk_sp<SkColorSpace> colorSpace = nullptr;
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
index 496c557..0683b39 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
@@ -20,6 +20,7 @@
 #include <SkSurface.h>
 #include <utils/FatVector.h>
 #include <utils/RefBase.h>
+#include <utils/Thread.h>
 #include <list>
 
 class GrRectanizer;
@@ -103,12 +104,19 @@
 
     /**
      * "releaseEntry" is invoked when a VectorDrawable is deleted. Passing a non-existing "atlasKey"
-     * is causing an undefined behaviour.
+     * is causing an undefined behaviour. This is the only function in the class that can be
+     * invoked from any thread. It will marshal internally to render thread if needed.
      */
     void releaseEntry(AtlasKey atlasKey);
 
     void setStorageMode(StorageMode mode);
 
+    /**
+     * "delayedReleaseEntries" is indirectly invoked by "releaseEntry", when "releaseEntry" is
+     * invoked from a non render thread.
+     */
+    void delayedReleaseEntries();
+
 private:
     struct CacheEntry {
         CacheEntry(const SkRect& newVDrect, const SkRect& newRect,
@@ -182,6 +190,17 @@
      */
     StorageMode mStorageMode;
 
+    /**
+     * mKeysForRelease is used by releaseEntry implementation to pass atlas keys from an arbitrary
+     * calling thread to the render thread.
+     */
+    std::vector<AtlasKey> mKeysForRelease;
+
+    /**
+     * A lock used to protect access to mKeysForRelease.
+     */
+    Mutex mReleaseKeyLock;
+
     sk_sp<SkSurface> createSurface(int width, int height, GrContext* context);
 
     inline bool fitInAtlas(int width, int height) {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 7fe966d..6904743 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -732,6 +732,18 @@
     thread.queue(task);
 }
 
+CREATE_BRIDGE1(releaseVDAtlasEntries, RenderThread* thread) {
+    args->thread->cacheManager().acquireVectorDrawableAtlas()->delayedReleaseEntries();
+    return nullptr;
+}
+
+void RenderProxy::releaseVDAtlasEntries() {
+    RenderThread& thread = RenderThread::getInstance();
+    SETUP_TASK(releaseVDAtlasEntries);
+    args->thread = &thread;
+    thread.queue(task);
+}
+
 void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) {
     void* retval;
     task->setReturnPtr(&retval);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 06eaebd..9440b15 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -143,6 +143,8 @@
 
     static void repackVectorDrawableAtlas();
 
+    static void releaseVDAtlasEntries();
+
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 72a428f..51e9374 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -499,6 +499,10 @@
     return nullptr;
 }
 
+bool RenderThread::isCurrent() {
+    return gettid() == getInstance().getTid();
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index bef47b3..30884b5 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -111,6 +111,14 @@
     sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap);
     void dumpGraphicsMemory(int fd);
 
+    /**
+     * isCurrent provides a way to query, if the caller is running on
+     * the render thread.
+     *
+     * @return true only if isCurrent is invoked from the render thread.
+     */
+    static bool isCurrent();
+
 protected:
     virtual bool threadLoop() override;