2
0

CAndroidVMHelper.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. * CAndroidVMHelper.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "CAndroidVMHelper.h"
  11. #ifdef VCMI_ANDROID
  12. static JavaVM * vmCache = nullptr;
  13. /// cached java classloader so that we can find our classes from other threads
  14. static jobject vcmiClassLoader;
  15. static jmethodID vcmiFindClassMethod;
  16. void CAndroidVMHelper::cacheVM(JNIEnv * env)
  17. {
  18. env->GetJavaVM(&vmCache);
  19. }
  20. void CAndroidVMHelper::cacheVM(JavaVM * vm)
  21. {
  22. vmCache = vm;
  23. }
  24. CAndroidVMHelper::CAndroidVMHelper()
  25. {
  26. auto res = vmCache->GetEnv((void **) &envPtr, JNI_VERSION_1_1);
  27. if(res == JNI_EDETACHED)
  28. {
  29. auto attachRes = vmCache->AttachCurrentThread(&envPtr, nullptr);
  30. if(attachRes == JNI_OK)
  31. {
  32. detachInDestructor = true; // only detach if we actually attached env
  33. }
  34. }
  35. else
  36. {
  37. detachInDestructor = false;
  38. }
  39. }
  40. CAndroidVMHelper::~CAndroidVMHelper()
  41. {
  42. Detach();
  43. }
  44. void CAndroidVMHelper::Detach()
  45. {
  46. if(envPtr && detachInDestructor)
  47. {
  48. vmCache->DetachCurrentThread();
  49. envPtr = nullptr;
  50. }
  51. }
  52. JNIEnv * CAndroidVMHelper::get()
  53. {
  54. return envPtr;
  55. }
  56. jclass CAndroidVMHelper::findClassloadedClass(const std::string & name)
  57. {
  58. auto env = get();
  59. return static_cast<jclass>(env->CallObjectMethod(vcmiClassLoader, vcmiFindClassMethod,
  60. env->NewStringUTF(name.c_str())));
  61. }
  62. void CAndroidVMHelper::callStaticVoidMethod(const std::string & cls, const std::string & method,
  63. bool classloaded)
  64. {
  65. auto env = get();
  66. auto javaHelper = findClass(cls, classloaded);
  67. auto methodId = env->GetStaticMethodID(javaHelper, method.c_str(), "()V");
  68. env->CallStaticVoidMethod(javaHelper, methodId);
  69. }
  70. std::string CAndroidVMHelper::callStaticStringMethod(const std::string & cls, const std::string & method,
  71. bool classloaded)
  72. {
  73. auto env = get();
  74. auto javaHelper = findClass(cls, classloaded);
  75. auto methodId = env->GetStaticMethodID(javaHelper, method.c_str(), "()Ljava/lang/String;");
  76. jstring jres = static_cast<jstring>(env->CallStaticObjectMethod(javaHelper, methodId));
  77. return std::string(env->GetStringUTFChars(jres, nullptr));
  78. }
  79. void CAndroidVMHelper::callCustomMethod(const std::string & cls, const std::string & method,
  80. const std::string & signature,
  81. std::function<void(JNIEnv *, jclass, jmethodID)> fun, bool classloaded)
  82. {
  83. auto env = get();
  84. auto javaHelper = findClass(cls, classloaded);
  85. auto methodId = env->GetStaticMethodID(javaHelper, method.c_str(), signature.c_str());
  86. fun(env, javaHelper, methodId);
  87. }
  88. jclass CAndroidVMHelper::findClass(const std::string & name, bool classloaded)
  89. {
  90. if(classloaded)
  91. {
  92. return findClassloadedClass(name);
  93. }
  94. return get()->FindClass(name.c_str());
  95. }
  96. extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_initClassloader(JNIEnv * baseEnv, jobject * cls)
  97. {
  98. CAndroidVMHelper::cacheVM(baseEnv);
  99. CAndroidVMHelper envHelper;
  100. auto env = envHelper.get();
  101. auto anyVCMIClass = env->FindClass(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS);
  102. jclass classClass = env->GetObjectClass(anyVCMIClass);
  103. auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
  104. auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
  105. vcmiClassLoader = (jclass) env->NewGlobalRef(env->CallObjectMethod(anyVCMIClass, getClassLoaderMethod));
  106. vcmiFindClassMethod = env->GetMethodID(classLoaderClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
  107. }
  108. #endif