/***************************************************************************** * Copyright (c) 2014-2020 OpenRCT2 developers * * For a complete list of all authors, please refer to contributors.md * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ #ifdef __ANDROID__ # include "../config/Config.h" # include "../localisation/Language.h" # include "../util/Util.h" # include "platform.h" # include # include # include AndroidClassLoader::AndroidClassLoader() { log_info("Obtaining JNI class loader"); // This is a workaround to be able to call JNI's ClassLoader from non-main // thread, based on https://stackoverflow.com/a/16302771 // Apparently it's OK to use it from across different thread, but JNI // only looks for ClassLoader in the _current_ thread and fails to find // it when searched for from a native library's non-main thread. // The solution below works by obtaining a ClassLoader reference in main // thread and caching it for future use from any thread, instead of using // it via env->FindClass(). ClassLoader itself is abstract, so we cannot // create it directly; instead we take an arbitrary class and call // getClassLoader() on it to create a reference that way. // If we're here, SDL's JNI_OnLoad has already been called and set env JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv(); // Take an arbitrary class. While the class does not really matter, it // makes sense to use one that's most likely already loaded and is unlikely // to be removed from code. auto randomClass = env->FindClass("io/openrct2/MainActivity"); jclass classClass = env->GetObjectClass(randomClass); // Get its class loader auto classLoaderClass = env->FindClass("java/lang/ClassLoader"); auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader", "()Ljava/lang/ClassLoader;"); // Store the class loader and its findClass method for future use _classLoader = env->NewGlobalRef(env->CallObjectMethod(randomClass, getClassLoaderMethod)); _findClassMethod = env->GetMethodID(classLoaderClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); } AndroidClassLoader::~AndroidClassLoader() { JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv(); env->DeleteGlobalRef(_classLoader); } jobject AndroidClassLoader::_classLoader; jmethodID AndroidClassLoader::_findClassMethod; static std::shared_ptr acl; void platform_android_init_class_loader() { acl = std::make_shared(); } jclass platform_android_find_class(JNIEnv* env, const char* name) { return static_cast( env->CallObjectMethod(AndroidClassLoader::_classLoader, AndroidClassLoader::_findClassMethod, env->NewStringUTF(name))); } #endif