summaryrefslogtreecommitdiffstats
path: root/platform/android
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2024-04-22 12:52:16 +0200
committerRémi Verschelde <rverschelde@gmail.com>2024-04-22 12:52:16 +0200
commit8c474ddd4999883749b987b2d4b4c70f00ebd94d (patch)
treec6602732cad5bf09c73b991b6ee8dc9548df924c /platform/android
parent4b6629978e8d1be15c5e3bc74db55900fa40f52e (diff)
parentf291a4ed3a64dd95bf8136f352e5d0554ada4a7c (diff)
downloadredot-engine-8c474ddd4999883749b987b2d4b4c70f00ebd94d.tar.gz
Merge pull request #90710 from m4gr3d/fix_jstring_leaks
Fix leakage of JNI object references
Diffstat (limited to 'platform/android')
-rw-r--r--platform/android/api/java_class_wrapper.h3
-rw-r--r--platform/android/api/jni_singleton.h11
-rw-r--r--platform/android/dir_access_jandroid.cpp8
-rw-r--r--platform/android/dir_access_jandroid.h1
-rw-r--r--platform/android/file_access_android.cpp17
-rw-r--r--platform/android/file_access_android.h10
-rw-r--r--platform/android/file_access_filesystem_jandroid.cpp8
-rw-r--r--platform/android/file_access_filesystem_jandroid.h1
-rw-r--r--platform/android/java_class_wrapper.cpp18
-rw-r--r--platform/android/java_godot_io_wrapper.cpp11
-rw-r--r--platform/android/java_godot_lib_jni.cpp12
-rw-r--r--platform/android/java_godot_view_wrapper.cpp1
-rw-r--r--platform/android/java_godot_wrapper.cpp20
-rw-r--r--platform/android/net_socket_android.cpp8
-rw-r--r--platform/android/net_socket_android.h1
-rw-r--r--platform/android/os_android.cpp4
-rw-r--r--platform/android/tts_android.cpp10
-rw-r--r--platform/android/tts_android.h1
18 files changed, 124 insertions, 21 deletions
diff --git a/platform/android/api/java_class_wrapper.h b/platform/android/api/java_class_wrapper.h
index b1481ebf7b..e21a331ab9 100644
--- a/platform/android/api/java_class_wrapper.h
+++ b/platform/android/api/java_class_wrapper.h
@@ -209,8 +209,6 @@ class JavaClassWrapper : public Object {
#ifdef ANDROID_ENABLED
RBMap<String, Ref<JavaClass>> class_cache;
friend class JavaClass;
- jclass activityClass;
- jmethodID findClass;
jmethodID getDeclaredMethods;
jmethodID getFields;
jmethodID getParameterTypes;
@@ -229,7 +227,6 @@ class JavaClassWrapper : public Object {
jmethodID Long_longValue;
jmethodID Float_floatValue;
jmethodID Double_doubleValue;
- jobject classLoader;
bool _get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, String &strsig);
#endif
diff --git a/platform/android/api/jni_singleton.h b/platform/android/api/jni_singleton.h
index a2d1c08168..5b30c392e7 100644
--- a/platform/android/api/jni_singleton.h
+++ b/platform/android/api/jni_singleton.h
@@ -241,6 +241,17 @@ public:
instance = nullptr;
#endif
}
+
+ ~JNISingleton() {
+#ifdef ANDROID_ENABLED
+ if (instance) {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL(env);
+
+ env->DeleteGlobalRef(instance);
+ }
+#endif
+ }
};
#endif // JNI_SINGLETON_H
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index 972a7dbe6a..ab90527bfa 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -321,6 +321,14 @@ void DirAccessJAndroid::setup(jobject p_dir_access_handler) {
_current_is_hidden = env->GetMethodID(cls, "isCurrentHidden", "(II)Z");
}
+void DirAccessJAndroid::terminate() {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL(env);
+
+ env->DeleteGlobalRef(cls);
+ env->DeleteGlobalRef(dir_access_handler);
+}
+
DirAccessJAndroid::DirAccessJAndroid() {
}
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index 9aaa78f38c..68578b0fa9 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/platform/android/dir_access_jandroid.h
@@ -89,6 +89,7 @@ public:
virtual uint64_t get_space_left() override;
static void setup(jobject p_dir_access_handler);
+ static void terminate();
DirAccessJAndroid();
~DirAccessJAndroid();
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index f56eda4694..ae336d6f9d 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -31,8 +31,12 @@
#include "file_access_android.h"
#include "core/string/print_string.h"
+#include "thread_jandroid.h"
+
+#include <android/asset_manager_jni.h>
AAssetManager *FileAccessAndroid::asset_manager = nullptr;
+jobject FileAccessAndroid::j_asset_manager = nullptr;
String FileAccessAndroid::get_path() const {
return path_src;
@@ -257,3 +261,16 @@ void FileAccessAndroid::close() {
FileAccessAndroid::~FileAccessAndroid() {
_close();
}
+
+void FileAccessAndroid::setup(jobject p_asset_manager) {
+ JNIEnv *env = get_jni_env();
+ j_asset_manager = env->NewGlobalRef(p_asset_manager);
+ asset_manager = AAssetManager_fromJava(env, j_asset_manager);
+}
+
+void FileAccessAndroid::terminate() {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL(env);
+
+ env->DeleteGlobalRef(j_asset_manager);
+}
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index bfe590b22f..e79daeafb3 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -35,9 +35,13 @@
#include <android/asset_manager.h>
#include <android/log.h>
+#include <jni.h>
#include <stdio.h>
class FileAccessAndroid : public FileAccess {
+ static AAssetManager *asset_manager;
+ static jobject j_asset_manager;
+
mutable AAsset *asset = nullptr;
mutable uint64_t len = 0;
mutable uint64_t pos = 0;
@@ -48,8 +52,6 @@ class FileAccessAndroid : public FileAccess {
void _close();
public:
- static AAssetManager *asset_manager;
-
virtual Error open_internal(const String &p_path, int p_mode_flags) override; // open a file
virtual bool is_open() const override; // true when file is open
@@ -93,6 +95,10 @@ public:
virtual void close() override;
+ static void setup(jobject p_asset_manager);
+
+ static void terminate();
+
~FileAccessAndroid();
};
diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp
index cc7acffdad..b66a201a12 100644
--- a/platform/android/file_access_filesystem_jandroid.cpp
+++ b/platform/android/file_access_filesystem_jandroid.cpp
@@ -408,6 +408,14 @@ void FileAccessFilesystemJAndroid::setup(jobject p_file_access_handler) {
_file_resize = env->GetMethodID(cls, "fileResize", "(IJ)I");
}
+void FileAccessFilesystemJAndroid::terminate() {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL(env);
+
+ env->DeleteGlobalRef(cls);
+ env->DeleteGlobalRef(file_access_handler);
+}
+
void FileAccessFilesystemJAndroid::close() {
if (is_open()) {
_close();
diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h
index 4a28b6e3d5..6a8fc524b7 100644
--- a/platform/android/file_access_filesystem_jandroid.h
+++ b/platform/android/file_access_filesystem_jandroid.h
@@ -97,6 +97,7 @@ public:
virtual bool file_exists(const String &p_path) override; ///< return true if a file exists
static void setup(jobject p_file_access_handler);
+ static void terminate();
virtual uint64_t _get_modified_time(const String &p_file) override;
virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index d6455cbf1c..a309a6ab74 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -1157,50 +1157,54 @@ JavaClassWrapper::JavaClassWrapper(jobject p_activity) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL(env);
- jclass activity = env->FindClass("android/app/Activity");
- jmethodID getClassLoader = env->GetMethodID(activity, "getClassLoader", "()Ljava/lang/ClassLoader;");
- classLoader = env->CallObjectMethod(p_activity, getClassLoader);
- classLoader = (jclass)env->NewGlobalRef(classLoader);
- jclass classLoaderClass = env->FindClass("java/lang/ClassLoader");
- findClass = env->GetMethodID(classLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
-
jclass bclass = env->FindClass("java/lang/Class");
getDeclaredMethods = env->GetMethodID(bclass, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;");
getFields = env->GetMethodID(bclass, "getFields", "()[Ljava/lang/reflect/Field;");
Class_getName = env->GetMethodID(bclass, "getName", "()Ljava/lang/String;");
+ env->DeleteLocalRef(bclass);
bclass = env->FindClass("java/lang/reflect/Method");
getParameterTypes = env->GetMethodID(bclass, "getParameterTypes", "()[Ljava/lang/Class;");
getReturnType = env->GetMethodID(bclass, "getReturnType", "()Ljava/lang/Class;");
getName = env->GetMethodID(bclass, "getName", "()Ljava/lang/String;");
getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
+ env->DeleteLocalRef(bclass);
bclass = env->FindClass("java/lang/reflect/Field");
Field_getName = env->GetMethodID(bclass, "getName", "()Ljava/lang/String;");
Field_getModifiers = env->GetMethodID(bclass, "getModifiers", "()I");
Field_get = env->GetMethodID(bclass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ env->DeleteLocalRef(bclass);
bclass = env->FindClass("java/lang/Boolean");
Boolean_booleanValue = env->GetMethodID(bclass, "booleanValue", "()Z");
+ env->DeleteLocalRef(bclass);
bclass = env->FindClass("java/lang/Byte");
Byte_byteValue = env->GetMethodID(bclass, "byteValue", "()B");
+ env->DeleteLocalRef(bclass);
bclass = env->FindClass("java/lang/Character");
Character_characterValue = env->GetMethodID(bclass, "charValue", "()C");
+ env->DeleteLocalRef(bclass);
bclass = env->FindClass("java/lang/Short");
Short_shortValue = env->GetMethodID(bclass, "shortValue", "()S");
+ env->DeleteLocalRef(bclass);
bclass = env->FindClass("java/lang/Integer");
Integer_integerValue = env->GetMethodID(bclass, "intValue", "()I");
+ env->DeleteLocalRef(bclass);
bclass = env->FindClass("java/lang/Long");
Long_longValue = env->GetMethodID(bclass, "longValue", "()J");
+ env->DeleteLocalRef(bclass);
bclass = env->FindClass("java/lang/Float");
Float_floatValue = env->GetMethodID(bclass, "floatValue", "()F");
+ env->DeleteLocalRef(bclass);
bclass = env->FindClass("java/lang/Double");
Double_doubleValue = env->GetMethodID(bclass, "doubleValue", "()D");
+ env->DeleteLocalRef(bclass);
}
diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
index 10716a5c79..49913b9c30 100644
--- a/platform/android/java_godot_io_wrapper.cpp
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -70,7 +70,11 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
}
GodotIOJavaWrapper::~GodotIOJavaWrapper() {
- // nothing to do here for now
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL(env);
+
+ env->DeleteGlobalRef(cls);
+ env->DeleteGlobalRef(godot_io_instance);
}
jobject GodotIOJavaWrapper::get_instance() {
@@ -82,7 +86,9 @@ Error GodotIOJavaWrapper::open_uri(const String &p_uri) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL_V(env, ERR_UNAVAILABLE);
jstring jStr = env->NewStringUTF(p_uri.utf8().get_data());
- return env->CallIntMethod(godot_io_instance, _open_URI, jStr) ? ERR_CANT_OPEN : OK;
+ Error result = env->CallIntMethod(godot_io_instance, _open_URI, jStr) ? ERR_CANT_OPEN : OK;
+ env->DeleteLocalRef(jStr);
+ return result;
} else {
return ERR_UNAVAILABLE;
}
@@ -220,6 +226,7 @@ void GodotIOJavaWrapper::show_vk(const String &p_existing, int p_type, int p_max
ERR_FAIL_NULL(env);
jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_type, p_max_input_length, p_cursor_start, p_cursor_end);
+ env->DeleteLocalRef(jStr);
}
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 2215f706c5..6cab7e74fd 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -95,6 +95,13 @@ static void _terminate(JNIEnv *env, bool p_restart = false) {
if (godot_io_java) {
delete godot_io_java;
}
+
+ TTS_Android::terminate();
+ FileAccessAndroid::terminate();
+ DirAccessJAndroid::terminate();
+ FileAccessFilesystemJAndroid::terminate();
+ NetSocketAndroid::terminate();
+
if (godot_java) {
if (!restart_on_cleanup) {
if (p_restart) {
@@ -125,10 +132,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv
init_thread_jandroid(jvm, env);
- jobject amgr = env->NewGlobalRef(p_asset_manager);
-
- FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr);
-
+ FileAccessAndroid::setup(p_asset_manager);
DirAccessJAndroid::setup(p_directory_access_handler);
FileAccessFilesystemJAndroid::setup(p_file_access_handler);
NetSocketAndroid::setup(p_net_utils);
diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp
index a95f762e01..04424c1179 100644
--- a/platform/android/java_godot_view_wrapper.cpp
+++ b/platform/android/java_godot_view_wrapper.cpp
@@ -95,6 +95,7 @@ void GodotJavaViewWrapper::configure_pointer_icon(int pointer_type, const String
jstring jImagePath = env->NewStringUTF(image_path.utf8().get_data());
env->CallVoidMethod(_godot_view, _configure_pointer_icon, pointer_type, jImagePath, p_hotspot.x, p_hotspot.y);
+ env->DeleteLocalRef(jImagePath);
}
}
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 3c950bb1b1..61be6fc5db 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -172,6 +172,8 @@ void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data());
jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data());
env->CallVoidMethod(godot_instance, _alert, jStrMessage, jStrTitle);
+ env->DeleteLocalRef(jStrMessage);
+ env->DeleteLocalRef(jStrTitle);
}
}
@@ -231,6 +233,7 @@ void GodotJavaWrapper::set_clipboard(const String &p_text) {
ERR_FAIL_NULL(env);
jstring jStr = env->NewStringUTF(p_text.utf8().get_data());
env->CallVoidMethod(godot_instance, _set_clipboard, jStr);
+ env->DeleteLocalRef(jStr);
}
}
@@ -253,7 +256,9 @@ bool GodotJavaWrapper::request_permission(const String &p_name) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL_V(env, false);
jstring jStrName = env->NewStringUTF(p_name.utf8().get_data());
- return env->CallBooleanMethod(godot_instance, _request_permission, jStrName);
+ bool result = env->CallBooleanMethod(godot_instance, _request_permission, jStrName);
+ env->DeleteLocalRef(jStrName);
+ return result;
} else {
return false;
}
@@ -340,7 +345,9 @@ int GodotJavaWrapper::create_new_godot_instance(const List<String> &args) {
ERR_FAIL_NULL_V(env, 0);
jobjectArray jargs = env->NewObjectArray(args.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
for (int i = 0; i < args.size(); i++) {
- env->SetObjectArrayElement(jargs, i, env->NewStringUTF(args[i].utf8().get_data()));
+ jstring j_arg = env->NewStringUTF(args[i].utf8().get_data());
+ env->SetObjectArrayElement(jargs, i, j_arg);
+ env->DeleteLocalRef(j_arg);
}
return env->CallIntMethod(godot_instance, _create_new_godot_instance, jargs);
} else {
@@ -355,6 +362,8 @@ void GodotJavaWrapper::begin_benchmark_measure(const String &p_context, const St
jstring j_context = env->NewStringUTF(p_context.utf8().get_data());
jstring j_label = env->NewStringUTF(p_label.utf8().get_data());
env->CallVoidMethod(godot_instance, _begin_benchmark_measure, j_context, j_label);
+ env->DeleteLocalRef(j_context);
+ env->DeleteLocalRef(j_label);
}
}
@@ -365,6 +374,8 @@ void GodotJavaWrapper::end_benchmark_measure(const String &p_context, const Stri
jstring j_context = env->NewStringUTF(p_context.utf8().get_data());
jstring j_label = env->NewStringUTF(p_label.utf8().get_data());
env->CallVoidMethod(godot_instance, _end_benchmark_measure, j_context, j_label);
+ env->DeleteLocalRef(j_context);
+ env->DeleteLocalRef(j_label);
}
}
@@ -374,6 +385,7 @@ void GodotJavaWrapper::dump_benchmark(const String &benchmark_file) {
ERR_FAIL_NULL(env);
jstring j_benchmark_file = env->NewStringUTF(benchmark_file.utf8().get_data());
env->CallVoidMethod(godot_instance, _dump_benchmark, j_benchmark_file);
+ env->DeleteLocalRef(j_benchmark_file);
}
}
@@ -383,7 +395,9 @@ bool GodotJavaWrapper::has_feature(const String &p_feature) const {
ERR_FAIL_NULL_V(env, false);
jstring j_feature = env->NewStringUTF(p_feature.utf8().get_data());
- return env->CallBooleanMethod(godot_instance, _has_feature, j_feature);
+ bool result = env->CallBooleanMethod(godot_instance, _has_feature, j_feature);
+ env->DeleteLocalRef(j_feature);
+ return result;
} else {
return false;
}
diff --git a/platform/android/net_socket_android.cpp b/platform/android/net_socket_android.cpp
index a2befdc9be..8f0ee51fac 100644
--- a/platform/android/net_socket_android.cpp
+++ b/platform/android/net_socket_android.cpp
@@ -49,6 +49,14 @@ void NetSocketAndroid::setup(jobject p_net_utils) {
_multicast_lock_release = env->GetMethodID(cls, "multicastLockRelease", "()V");
}
+void NetSocketAndroid::terminate() {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL(env);
+
+ env->DeleteGlobalRef(cls);
+ env->DeleteGlobalRef(net_utils);
+}
+
void NetSocketAndroid::multicast_lock_acquire() {
if (_multicast_lock_acquire) {
JNIEnv *env = get_jni_env();
diff --git a/platform/android/net_socket_android.h b/platform/android/net_socket_android.h
index e5f46d3236..26cb2d4e3d 100644
--- a/platform/android/net_socket_android.h
+++ b/platform/android/net_socket_android.h
@@ -63,6 +63,7 @@ protected:
public:
static void make_default();
static void setup(jobject p_net_utils);
+ static void terminate();
virtual void close();
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 1583e655d8..463a307854 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -776,6 +776,10 @@ void OS_Android::benchmark_dump() {
}
bool OS_Android::_check_internal_feature_support(const String &p_feature) {
+ if (p_feature == "macos" || p_feature == "web_ios" || p_feature == "web_macos" || p_feature == "windows") {
+ return false;
+ }
+
if (p_feature == "system_fonts") {
return true;
}
diff --git a/platform/android/tts_android.cpp b/platform/android/tts_android.cpp
index 93517d8045..be85e47972 100644
--- a/platform/android/tts_android.cpp
+++ b/platform/android/tts_android.cpp
@@ -77,6 +77,14 @@ void TTS_Android::setup(jobject p_tts) {
}
}
+void TTS_Android::terminate() {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL(env);
+
+ env->DeleteGlobalRef(cls);
+ env->DeleteGlobalRef(tts);
+}
+
void TTS_Android::_java_utterance_callback(int p_event, int p_id, int p_pos) {
ERR_FAIL_COND_MSG(!initialized, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
if (ids.has(p_id)) {
@@ -170,6 +178,8 @@ void TTS_Android::speak(const String &p_text, const String &p_voice, int p_volum
jstring jStrT = env->NewStringUTF(p_text.utf8().get_data());
jstring jStrV = env->NewStringUTF(p_voice.utf8().get_data());
env->CallVoidMethod(tts, _speak, jStrT, jStrV, CLAMP(p_volume, 0, 100), CLAMP(p_pitch, 0.f, 2.f), CLAMP(p_rate, 0.1f, 10.f), p_utterance_id, p_interrupt);
+ env->DeleteLocalRef(jStrT);
+ env->DeleteLocalRef(jStrV);
}
}
diff --git a/platform/android/tts_android.h b/platform/android/tts_android.h
index 39efef6ed1..4cc7c12846 100644
--- a/platform/android/tts_android.h
+++ b/platform/android/tts_android.h
@@ -57,6 +57,7 @@ class TTS_Android {
public:
static void setup(jobject p_tts);
+ static void terminate();
static void _java_utterance_callback(int p_event, int p_id, int p_pos);
static bool is_speaking();