Skip to content

Commit 766781c

Browse files
committed
Harden AndroidSDK in case of plugin destruction
1 parent c354130 commit 766781c

File tree

3 files changed

+87
-15
lines changed

3 files changed

+87
-15
lines changed

android_lib/src/main/java/io/sentry/godotplugin/SentryAndroidGodotPlugin.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,20 @@ class SentryAndroidGodotPlugin(godot: Godot) : GodotPlugin(godot) {
130130
return "SentryAndroidGodotPlugin"
131131
}
132132

133+
private var destroyHandlerId: Long = 0
134+
135+
@UsedByGodot
136+
fun registerDestroyHandler(handlerId: Long) {
137+
destroyHandlerId = handlerId
138+
}
139+
140+
override fun onMainDestroy() {
141+
if (destroyHandlerId != 0L) {
142+
Callable.call(destroyHandlerId, "notify_plugin_destroyed")
143+
}
144+
super.onMainDestroy()
145+
}
146+
133147
@UsedByGodot
134148
fun init(
135149
optionsData: Dictionary,

src/sentry/android/android_sdk.cpp

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,30 +74,49 @@ void SentryAndroidBeforeSendLogHandler::_bind_methods() {
7474
ClassDB::bind_method(D_METHOD("before_send_log"), &SentryAndroidBeforeSendLogHandler::_before_send_log);
7575
}
7676

77+
// *** SentryAndroidPluginDestroyedHandler
78+
79+
void SentryAndroidPluginDestroyedHandler::_initialize(std::function<void()> p_callback) {
80+
callback = p_callback;
81+
}
82+
83+
void SentryAndroidPluginDestroyedHandler::_notify_plugin_destroyed() {
84+
callback();
85+
}
86+
87+
void SentryAndroidPluginDestroyedHandler::_bind_methods() {
88+
ClassDB::bind_method(D_METHOD("notify_plugin_destroyed"), &SentryAndroidPluginDestroyedHandler::_notify_plugin_destroyed);
89+
}
90+
7791
// *** AndroidSDK
7892

93+
void AndroidSDK::_notify_plugin_destroyed() {
94+
sentry::logging::print_debug("Android bridge plugin destroyed");
95+
plugin_alive.store(false);
96+
}
97+
7998
void AndroidSDK::set_context(const String &p_key, const Dictionary &p_value) {
80-
ERR_FAIL_NULL(android_plugin);
99+
ERR_FAIL_COND(!_is_plugin_alive());
81100
android_plugin->call(ANDROID_SN(setContext), p_key, sanitize_variant(p_value));
82101
}
83102

84103
void AndroidSDK::remove_context(const String &p_key) {
85-
ERR_FAIL_NULL(android_plugin);
104+
ERR_FAIL_COND(!_is_plugin_alive());
86105
android_plugin->call(ANDROID_SN(removeContext), p_key);
87106
}
88107

89108
void AndroidSDK::set_tag(const String &p_key, const String &p_value) {
90-
ERR_FAIL_NULL(android_plugin);
109+
ERR_FAIL_COND(!_is_plugin_alive());
91110
android_plugin->call(ANDROID_SN(setTag), p_key, p_value);
92111
}
93112

94113
void AndroidSDK::remove_tag(const String &p_key) {
95-
ERR_FAIL_NULL(android_plugin);
114+
ERR_FAIL_COND(!_is_plugin_alive());
96115
android_plugin->call(ANDROID_SN(removeTag), p_key);
97116
}
98117

99118
void AndroidSDK::set_user(const Ref<SentryUser> &p_user) {
100-
ERR_FAIL_NULL(android_plugin);
119+
ERR_FAIL_COND(!_is_plugin_alive());
101120

102121
if (p_user.is_valid()) {
103122
android_plugin->call(ANDROID_SN(setUser),
@@ -111,26 +130,26 @@ void AndroidSDK::set_user(const Ref<SentryUser> &p_user) {
111130
}
112131

113132
void AndroidSDK::remove_user() {
114-
ERR_FAIL_NULL(android_plugin);
133+
ERR_FAIL_COND(!_is_plugin_alive());
115134
android_plugin->call(ANDROID_SN(removeUser));
116135
}
117136

118137
Ref<SentryBreadcrumb> AndroidSDK::create_breadcrumb() {
119-
ERR_FAIL_NULL_V(android_plugin, nullptr);
138+
ERR_FAIL_COND_V(!_is_plugin_alive(), nullptr);
120139
int32_t handle = android_plugin->call(ANDROID_SN(createBreadcrumb));
121140
Ref<AndroidBreadcrumb> crumb = memnew(AndroidBreadcrumb(android_plugin, handle));
122141
return crumb;
123142
}
124143

125144
void AndroidSDK::add_breadcrumb(const Ref<SentryBreadcrumb> &p_breadcrumb) {
126-
ERR_FAIL_NULL(android_plugin);
145+
ERR_FAIL_COND(!_is_plugin_alive());
127146
Ref<AndroidBreadcrumb> crumb = p_breadcrumb;
128147
ERR_FAIL_COND(crumb.is_null());
129148
android_plugin->call(ANDROID_SN(addBreadcrumb), crumb->get_handle());
130149
}
131150

132151
void AndroidSDK::log(LogLevel p_level, const String &p_body, const Dictionary &p_attributes) {
133-
ERR_FAIL_NULL(android_plugin);
152+
ERR_FAIL_COND(!_is_plugin_alive());
134153

135154
if (p_body.is_empty()) {
136155
return;
@@ -152,24 +171,24 @@ void AndroidSDK::log(LogLevel p_level, const String &p_body, const Dictionary &p
152171
}
153172

154173
String AndroidSDK::capture_message(const String &p_message, Level p_level) {
155-
ERR_FAIL_NULL_V(android_plugin, String());
174+
ERR_FAIL_COND_V(!_is_plugin_alive(), String());
156175
return android_plugin->call(ANDROID_SN(captureMessage), p_message, p_level);
157176
}
158177

159178
String AndroidSDK::get_last_event_id() {
160-
ERR_FAIL_NULL_V(android_plugin, String());
179+
ERR_FAIL_COND_V(!_is_plugin_alive(), String());
161180
return android_plugin->call(ANDROID_SN(getLastEventId));
162181
}
163182

164183
Ref<SentryEvent> AndroidSDK::create_event() {
165-
ERR_FAIL_NULL_V(android_plugin, nullptr);
184+
ERR_FAIL_COND_V(!_is_plugin_alive(), nullptr);
166185
int32_t event_handle = android_plugin->call(ANDROID_SN(createEvent));
167186
Ref<AndroidEvent> event = memnew(AndroidEvent(android_plugin, event_handle));
168187
return event;
169188
}
170189

171190
String AndroidSDK::capture_event(const Ref<SentryEvent> &p_event) {
172-
ERR_FAIL_NULL_V(android_plugin, String());
191+
ERR_FAIL_COND_V(!_is_plugin_alive(), String());
173192
ERR_FAIL_COND_V(p_event.is_null(), String());
174193
Ref<AndroidEvent> android_event = p_event;
175194
ERR_FAIL_COND_V(android_event.is_null(), String());
@@ -179,7 +198,7 @@ String AndroidSDK::capture_event(const Ref<SentryEvent> &p_event) {
179198
}
180199

181200
void AndroidSDK::capture_feedback(const Ref<SentryFeedback> &p_feedback) {
182-
ERR_FAIL_NULL(android_plugin);
201+
ERR_FAIL_COND(!_is_plugin_alive());
183202
ERR_FAIL_COND_MSG(p_feedback.is_null(), "Sentry: Can't capture feedback - feedback object is null.");
184203
ERR_FAIL_COND_MSG(p_feedback->get_message().is_empty(), "Sentry: Can't capture feedback - feedback message is empty.");
185204
android_plugin->call(ANDROID_SN(captureFeedback),
@@ -190,6 +209,7 @@ void AndroidSDK::capture_feedback(const Ref<SentryFeedback> &p_feedback) {
190209
}
191210

192211
void AndroidSDK::add_attachment(const Ref<SentryAttachment> &p_attachment) {
212+
ERR_FAIL_COND(!_is_plugin_alive());
193213
ERR_FAIL_COND(p_attachment.is_null());
194214

195215
if (p_attachment->get_path().is_empty()) {
@@ -211,7 +231,7 @@ void AndroidSDK::add_attachment(const Ref<SentryAttachment> &p_attachment) {
211231
}
212232

213233
void AndroidSDK::init(const PackedStringArray &p_global_attachments, const Callable &p_configuration_callback) {
214-
ERR_FAIL_NULL(android_plugin);
234+
ERR_FAIL_COND(!_is_plugin_alive());
215235

216236
if (p_configuration_callback.is_valid()) {
217237
p_configuration_callback.call(SentryOptions::get_singleton());
@@ -264,8 +284,16 @@ AndroidSDK::AndroidSDK() {
264284
AndroidStringNames::create_singleton();
265285

266286
android_plugin = Engine::get_singleton()->get_singleton("SentryAndroidGodotPlugin");
287+
plugin_alive.store(android_plugin != nullptr);
288+
267289
ERR_FAIL_NULL_MSG(android_plugin, "Sentry: Unable to locate SentryAndroidGodotPlugin singleton.");
268290

291+
plugin_destroyed_handler = memnew(SentryAndroidPluginDestroyedHandler);
292+
plugin_destroyed_handler->_initialize([this]() {
293+
_notify_plugin_destroyed();
294+
});
295+
android_plugin->call("registerDestroyHandler", plugin_destroyed_handler->get_instance_id());
296+
269297
before_send_handler = memnew(SentryAndroidBeforeSendHandler);
270298
before_send_handler->_initialize(android_plugin);
271299

@@ -277,9 +305,15 @@ AndroidSDK::~AndroidSDK() {
277305
AndroidStringNames::destroy_singleton();
278306
if (before_send_handler) {
279307
memdelete(before_send_handler);
308+
before_send_handler = nullptr;
280309
}
281310
if (before_send_log_handler) {
282311
memdelete(before_send_log_handler);
312+
before_send_log_handler = nullptr;
313+
}
314+
if (plugin_destroyed_handler) {
315+
memdelete(plugin_destroyed_handler);
316+
plugin_destroyed_handler = nullptr;
283317
}
284318
android_plugin = nullptr;
285319
}

src/sentry/android/android_sdk.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
#include "sentry/internal_sdk.h"
55

6+
#include <atomic>
7+
#include <functional>
8+
69
using namespace godot;
710

811
namespace sentry::android {
@@ -37,12 +40,33 @@ class SentryAndroidBeforeSendLogHandler : public Object {
3740
static void _bind_methods();
3841
};
3942

43+
class SentryAndroidPluginDestroyedHandler : public Object {
44+
GDCLASS(SentryAndroidPluginDestroyedHandler, Object);
45+
friend class AndroidSDK;
46+
47+
private:
48+
std::function<void()> callback;
49+
50+
void _initialize(std::function<void()> p_callback);
51+
52+
void _notify_plugin_destroyed();
53+
54+
protected:
55+
static void _bind_methods();
56+
};
57+
4058
// Internal SDK utilizing Sentry Android (sentry-java repo).
4159
class AndroidSDK : public InternalSDK {
4260
private:
4361
Object *android_plugin = nullptr;
62+
std::atomic<bool> plugin_alive;
63+
_FORCE_INLINE_ bool _is_plugin_alive() const { return plugin_alive.load(); }
64+
4465
SentryAndroidBeforeSendHandler *before_send_handler = nullptr;
4566
SentryAndroidBeforeSendLogHandler *before_send_log_handler = nullptr;
67+
SentryAndroidPluginDestroyedHandler *plugin_destroyed_handler = nullptr;
68+
69+
void _notify_plugin_destroyed();
4670

4771
public:
4872
virtual void set_context(const String &p_key, const Dictionary &p_value) override;

0 commit comments

Comments
 (0)