Add MapRenderer dangling reference check (#3541)

Co-authored-by: Bart Louwers <bart.louwers@gmail.com>
This commit is contained in:
Adrian Cojocaru
2025-06-11 01:27:09 +03:00
committed by GitHub
parent 6704f0f80a
commit 7b8f7458ca
5 changed files with 48 additions and 17 deletions

View File

@@ -9,8 +9,10 @@
#include <mbgl/util/instrumentation.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/thread.hpp>
#include <mbgl/util/logging.hpp>
#include "android_renderer_backend.hpp"
#include "attach_env.hpp"
namespace mbgl {
namespace android {
@@ -91,23 +93,38 @@ private:
ActorRef<RendererObserver> delegate;
};
AndroidRendererFrontend::AndroidRendererFrontend(Private, MapRenderer& mapRenderer_)
: mapRenderer(mapRenderer_),
AndroidRendererFrontend::AndroidRendererFrontend(Private,
jni::JNIEnv& env,
const jni::Object<MapRenderer>& mapRendererObj)
: mapRenderer(MapRenderer::getNativePeer(env, mapRendererObj)),
mapRunLoop(util::RunLoop::Get()) {}
std::shared_ptr<AndroidRendererFrontend> AndroidRendererFrontend::create(MapRenderer& mapRenderer) {
auto ptr = std::make_shared<AndroidRendererFrontend>(Private(), mapRenderer);
ptr->init();
std::shared_ptr<AndroidRendererFrontend> AndroidRendererFrontend::create(
jni::JNIEnv& env, const jni::Object<MapRenderer>& mapRendererObj) {
auto ptr = std::make_shared<AndroidRendererFrontend>(Private(), env, mapRendererObj);
ptr->init(env, mapRendererObj);
return ptr;
}
void AndroidRendererFrontend::init() {
updateAsyncTask = std::make_unique<util::AsyncTask>([weakSelf = weak_from_this()]() {
if (auto self = weakSelf.lock()) {
self->mapRenderer.update(std::move(self->updateParams));
self->mapRenderer.requestRender();
}
});
void AndroidRendererFrontend::init(jni::JNIEnv& env, const jni::Object<MapRenderer>& mapRendererObj) {
auto weakMapRenderer = std::make_shared<jni::WeakReference<jni::Object<MapRenderer>>>(env, mapRendererObj);
updateAsyncTask = std::make_unique<util::AsyncTask>(
[weakSelf = weak_from_this(), weakMapRenderer = std::move(weakMapRenderer)]() {
if (auto self = weakSelf.lock()) {
try {
android::UniqueEnv _env = android::AttachEnv();
auto mapRendererRef = weakMapRenderer->get(*_env);
if (mapRendererRef) {
self->mapRenderer.update(std::move(self->updateParams));
self->mapRenderer.requestRender(*_env, mapRendererRef);
}
} catch (const std::exception& exception) {
Log::Error(Event::Android,
std::string("AndroidRendererFrontend::updateAsyncTask failed: ") + exception.what());
}
}
});
}
AndroidRendererFrontend::~AndroidRendererFrontend() = default;

View File

@@ -14,6 +14,8 @@
#include "map_renderer.hpp"
#include <jni/jni.hpp>
namespace mbgl {
class RenderedQueryOptions;
@@ -33,10 +35,9 @@ class AndroidRendererFrontend : public RendererFrontend, public std::enable_shar
};
public:
AndroidRendererFrontend(Private, MapRenderer&);
static std::shared_ptr<AndroidRendererFrontend> create(MapRenderer&);
void init();
AndroidRendererFrontend(Private, jni::JNIEnv&, const jni::Object<MapRenderer>&);
static std::shared_ptr<AndroidRendererFrontend> create(jni::JNIEnv&, const jni::Object<MapRenderer>&);
void init(jni::JNIEnv&, const jni::Object<MapRenderer>&);
~AndroidRendererFrontend() override;

View File

@@ -138,6 +138,18 @@ void MapRenderer::requestRender() {
}
}
void MapRenderer::requestRender(JNIEnv& env, jni::Local<jni::Object<MapRenderer>>& ref) {
try {
static auto& javaClass = jni::Class<MapRenderer>::Singleton(env);
static auto onInvalidate = javaClass.GetMethod<void()>(env, "requestRender");
if (ref) {
ref.Call(env, onInvalidate);
}
} catch (const std::exception& exception) {
Log::Error(Event::Android, std::string("MapRenderer::requestRender failed: ") + exception.what());
}
}
void MapRenderer::update(std::shared_ptr<UpdateParameters> params) {
try {
// Lock on the parameters

View File

@@ -81,6 +81,7 @@ public:
void waitForEmpty(const util::SimpleIdentity tag) override;
void requestRender();
void requestRender(JNIEnv&, jni::Local<jni::Object<MapRenderer>>&);
// Snapshot - requires a RunLoop on the calling thread
using SnapshotCallback = std::function<void(PremultipliedImage)>;

View File

@@ -75,7 +75,7 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
}
// Create a renderer frontend
rendererFrontend = AndroidRendererFrontend::create(mapRenderer);
rendererFrontend = AndroidRendererFrontend::create(_env, jMapRenderer);
// Create Map options
MapOptions options;