浏览代码

fix using JNI from server in single process build

Andrey Filipenkov 2 年之前
父节点
当前提交
313d479d42
共有 6 个文件被更改,包括 38 次插入7 次删除
  1. 18 3
      client/mainmenu/CMainMenu.cpp
  2. 2 1
      client/mainmenu/CMainMenu.h
  3. 3 1
      lib/CAndroidVMHelper.cpp
  4. 2 0
      lib/CAndroidVMHelper.h
  5. 9 1
      server/CVCMIServer.cpp
  6. 4 1
      server/CVCMIServer.h

+ 18 - 3
client/mainmenu/CMainMenu.cpp

@@ -53,6 +53,10 @@
 #include "../../lib/CondSh.h"
 #include "../../lib/CondSh.h"
 #include "../../lib/mapping/CCampaignHandler.h"
 #include "../../lib/mapping/CCampaignHandler.h"
 
 
+#if defined(SINGLE_PROCESS_APP) && defined(VCMI_ANDROID)
+#include "../../server/CVCMIServer.h"
+#include <SDL.h>
+#endif
 
 
 namespace fs = boost::filesystem;
 namespace fs = boost::filesystem;
 
 
@@ -459,7 +463,7 @@ CSimpleJoinScreen::CSimpleJoinScreen(bool host)
 	if(host && !settings["session"]["donotstartserver"].Bool())
 	if(host && !settings["session"]["donotstartserver"].Bool())
 	{
 	{
 		textTitle->setText("Connecting...");
 		textTitle->setText("Connecting...");
-		boost::thread(&CSimpleJoinScreen::connectThread, this, "", 0);
+		startConnectThread();
 	}
 	}
 	else
 	else
 	{
 	{
@@ -484,7 +488,7 @@ void CSimpleJoinScreen::connectToServer()
 	buttonOk->block(true);
 	buttonOk->block(true);
 	GH.stopTextInput();
 	GH.stopTextInput();
 
 
-	boost::thread(&CSimpleJoinScreen::connectThread, this, inputAddress->getText(), boost::lexical_cast<ui16>(inputPort->getText()));
+	startConnectThread(inputAddress->getText(), boost::lexical_cast<ui16>(inputPort->getText()));
 }
 }
 
 
 void CSimpleJoinScreen::leaveScreen()
 void CSimpleJoinScreen::leaveScreen()
@@ -505,7 +509,18 @@ void CSimpleJoinScreen::onChange(const std::string & newText)
 	buttonOk->block(inputAddress->getText().empty() || inputPort->getText().empty());
 	buttonOk->block(inputAddress->getText().empty() || inputPort->getText().empty());
 }
 }
 
 
-void CSimpleJoinScreen::connectThread(const std::string addr, const ui16 port)
+void CSimpleJoinScreen::startConnectThread(const std::string & addr, ui16 port)
+{
+#if defined(SINGLE_PROCESS_APP) && defined(VCMI_ANDROID)
+	// in single process build server must use same JNIEnv as client
+	// as server runs in a separate thread, it must not attempt to search for Java classes (and they're already cached anyway)
+	// https://github.com/libsdl-org/SDL/blob/main/docs/README-android.md#threads-and-the-java-vm
+	CVCMIServer::reuseClientJNIEnv(SDL_AndroidGetJNIEnv());
+#endif
+	boost::thread(&CSimpleJoinScreen::connectThread, this, addr, port);
+}
+
+void CSimpleJoinScreen::connectThread(const std::string & addr, ui16 port)
 {
 {
 	setThreadName("CSimpleJoinScreen::connectThread");
 	setThreadName("CSimpleJoinScreen::connectThread");
 	if(!addr.length())
 	if(!addr.length())

+ 2 - 1
client/mainmenu/CMainMenu.h

@@ -167,7 +167,8 @@ class CSimpleJoinScreen : public WindowBase
 	void connectToServer();
 	void connectToServer();
 	void leaveScreen();
 	void leaveScreen();
 	void onChange(const std::string & newText);
 	void onChange(const std::string & newText);
-	void connectThread(const std::string addr = "", const ui16 inputPort = 0);
+	void startConnectThread(const std::string & addr = {}, ui16 port = 0);
+	void connectThread(const std::string & addr, ui16 port);
 
 
 public:
 public:
 	CSimpleJoinScreen(bool host = true);
 	CSimpleJoinScreen(bool host = true);

+ 3 - 1
lib/CAndroidVMHelper.cpp

@@ -18,6 +18,8 @@ static JavaVM * vmCache = nullptr;
 static jobject vcmiClassLoader;
 static jobject vcmiClassLoader;
 static jmethodID vcmiFindClassMethod;
 static jmethodID vcmiFindClassMethod;
 
 
+bool CAndroidVMHelper::alwaysUseLoadedClass = false;
+
 void CAndroidVMHelper::cacheVM(JNIEnv * env)
 void CAndroidVMHelper::cacheVM(JNIEnv * env)
 {
 {
 	env->GetJavaVM(&vmCache);
 	env->GetJavaVM(&vmCache);
@@ -91,7 +93,7 @@ void CAndroidVMHelper::callCustomMethod(const std::string & cls, const std::stri
 
 
 jclass CAndroidVMHelper::findClass(const std::string & name, bool classloaded)
 jclass CAndroidVMHelper::findClass(const std::string & name, bool classloaded)
 {
 {
-	if(classloaded)
+	if(alwaysUseLoadedClass || classloaded)
 	{
 	{
 		return findClassloadedClass(name);
 		return findClassloadedClass(name);
 	}
 	}

+ 2 - 0
lib/CAndroidVMHelper.h

@@ -46,6 +46,8 @@ public:
 
 
 	static void initClassloader(void * baseEnv);
 	static void initClassloader(void * baseEnv);
 	
 	
+	static bool alwaysUseLoadedClass;
+
 	static constexpr const char * NATIVE_METHODS_DEFAULT_CLASS = "eu/vcmi/vcmi/NativeMethods";
 	static constexpr const char * NATIVE_METHODS_DEFAULT_CLASS = "eu/vcmi/vcmi/NativeMethods";
 };
 };
 
 

+ 9 - 1
server/CVCMIServer.cpp

@@ -1191,4 +1191,12 @@ void CVCMIServer::create(boost::condition_variable * cond, const std::vector<std
 		argv.push_back(a.c_str());
 		argv.push_back(a.c_str());
 	main(argv.size(), reinterpret_cast<const char **>(&*argv.begin()));
 	main(argv.size(), reinterpret_cast<const char **>(&*argv.begin()));
 }
 }
-#endif
+
+#ifdef VCMI_ANDROID
+void CVCMIServer::reuseClientJNIEnv(void * jniEnv)
+{
+	CAndroidVMHelper::initClassloader(jniEnv);
+	CAndroidVMHelper::alwaysUseLoadedClass = true;
+}
+#endif // VCMI_ANDROID
+#endif // VCMI_ANDROID_DUAL_PROCESS

+ 4 - 1
server/CVCMIServer.h

@@ -121,5 +121,8 @@ public:
 	static void create();
 	static void create();
 #elif defined(SINGLE_PROCESS_APP)
 #elif defined(SINGLE_PROCESS_APP)
 	static void create(boost::condition_variable * cond, const std::vector<std::string> & args);
 	static void create(boost::condition_variable * cond, const std::vector<std::string> & args);
-#endif
+# ifdef VCMI_ANDROID
+	static void reuseClientJNIEnv(void * jniEnv);
+# endif // VCMI_ANDROID
+#endif // VCMI_ANDROID_DUAL_PROCESS
 };
 };