From e3cf20e1cc5645646f7216733e97b4c7660d2df8 Mon Sep 17 00:00:00 2001
From: Susko3 <[EMAIL REDACTED]>
Date: Sat, 3 Aug 2024 15:34:38 +0200
Subject: [PATCH] Remove `createSDLMainRunnable()` in favour of `main()` to fix
multiple issues when providing custom main/runnable code (#10434)
This allows managed applications (eg. Java, C#) to override main() to their liking.
---
.../main/java/org/libsdl/app/SDLActivity.java | 34 +++++++++--------
src/core/android/SDL_android.c | 38 +++++++++++++------
2 files changed, 46 insertions(+), 26 deletions(-)
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
index 134a3dfdcf604..b7d4bde0eee8c 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
@@ -247,12 +247,19 @@ protected static SDLGenericMotionListener_API12 getMotionListener() {
}
/**
- * This method creates a Runnable which invokes SDL_main. The default implementation
- * uses the getMainSharedObject() and getMainFunction() methods to invoke native
- * code from the specified shared library.
+ * The application entry point, called on a dedicated thread (SDLThread).
+ * The default implementation uses the getMainSharedObject() and getMainFunction() methods
+ * to invoke native code from the specified shared library.
+ * It can be overridden by derived classes.
*/
- protected Runnable createSDLMainRunnable() {
- return new SDLMain();
+ protected void main() {
+ String library = SDLActivity.mSingleton.getMainSharedObject();
+ String function = SDLActivity.mSingleton.getMainFunction();
+ String[] arguments = SDLActivity.mSingleton.getArguments();
+
+ Log.v("SDL", "Running main function " + function + " from library " + library);
+ SDLActivity.nativeRunMain(library, function, arguments);
+ Log.v("SDL", "Finished main function");
}
/**
@@ -838,7 +845,7 @@ public static void handleNativeState() {
// Start up the C app thread and enable sensor input for the first time
// FIXME: Why aren't we enabling sensor input at start?
- mSDLThread = new Thread(SDLActivity.mSingleton.createSDLMainRunnable(), "SDLThread");
+ mSDLThread = new Thread(new SDLMain(), "SDLThread");
mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
mSDLThread.start();
@@ -1032,6 +1039,8 @@ protected boolean sendCommand(int command, Object data) {
// C functions we call
public static native String nativeGetVersion();
public static native int nativeSetupJNI();
+ public static native void nativeInitMainThread();
+ public static native void nativeCleanupMainThread();
public static native int nativeRunMain(String library, String function, Object arguments);
public static native void nativeLowMemory();
public static native void nativeSendQuit();
@@ -2102,10 +2111,7 @@ static class SDLFileDialogState {
class SDLMain implements Runnable {
@Override
public void run() {
- // Runs SDL_main()
- String library = SDLActivity.mSingleton.getMainSharedObject();
- String function = SDLActivity.mSingleton.getMainFunction();
- String[] arguments = SDLActivity.mSingleton.getArguments();
+ // Runs SDLActivity.main()
try {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_DISPLAY);
@@ -2113,11 +2119,9 @@ public void run() {
Log.v("SDL", "modify thread properties failed " + e.toString());
}
- Log.v("SDL", "Running main function " + function + " from library " + library);
-
- SDLActivity.nativeRunMain(library, function, arguments);
-
- Log.v("SDL", "Finished main function");
+ SDLActivity.nativeInitMainThread();
+ SDLActivity.mSingleton.main();
+ SDLActivity.nativeCleanupMainThread();
if (SDLActivity.mSingleton != null && !SDLActivity.mSingleton.isFinishing()) {
// Let's finish the Activity
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index bf0f30b986114..7cb4f9a303a18 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -64,6 +64,12 @@ JNIEXPORT jstring JNICALL SDL_JAVA_INTERFACE(nativeGetVersion)(
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(
JNIEnv *env, jclass cls);
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeInitSDLThread)(
+ JNIEnv *env, jclass cls);
+
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeCleanupSDLThread)(
+ JNIEnv *env, jclass cls);
+
JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(
JNIEnv *env, jclass cls,
jstring library, jstring function, jobject array);
@@ -188,6 +194,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeFileDialog)(
static JNINativeMethod SDLActivity_tab[] = {
{ "nativeGetVersion", "()Ljava/lang/String;", SDL_JAVA_INTERFACE(nativeGetVersion) },
{ "nativeSetupJNI", "()I", SDL_JAVA_INTERFACE(nativeSetupJNI) },
+ { "nativeInitSDLThread", "()V", SDL_JAVA_INTERFACE(nativeInitSDLThread) },
+ { "nativeCleanupSDLThread", "()V", SDL_JAVA_INTERFACE(nativeCleanupSDLThread) },
{ "nativeRunMain", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)I", SDL_JAVA_INTERFACE(nativeRunMain) },
{ "onNativeDropFile", "(Ljava/lang/String;)V", SDL_JAVA_INTERFACE(onNativeDropFile) },
{ "nativeSetScreenResolution", "(IIIIFF)V", SDL_JAVA_INTERFACE(nativeSetScreenResolution) },
@@ -764,14 +772,10 @@ JNIEXPORT jboolean JNICALL SDL_JAVA_INTERFACE(nativeAllowRecreateActivity)(
return SDL_AtomicGet(&bAllowRecreateActivity);
}
-/* Start up the SDL app */
-JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls, jstring library, jstring function, jobject array)
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeInitSDLThread)(
+ JNIEnv *env, jclass jcls)
{
- int status = -1;
- const char *library_file;
- void *library_handle;
-
- __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeRunMain() %d time", run_count);
+ __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeInitSDLThread() %d time", run_count);
if (run_count == 1) {
SDL_AddHintCallback(SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY, SDL_AllowRecreateActivityChanged, NULL);
}
@@ -779,6 +783,22 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls,
/* Save JNIEnv of SDLThread */
Android_JNI_SetEnv(env);
+}
+
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeCleanupSDLThread)(
+ JNIEnv *env, jclass jcls)
+{
+ /* This is a Java thread, it doesn't need to be Detached from the JVM.
+ * Set to mThreadKey value to NULL not to call pthread_create destructor 'Android_JNI_ThreadDestroyed' */
+ Android_JNI_SetEnv(NULL);
+}
+
+/* Start up the SDL app */
+JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls, jstring library, jstring function, jobject array)
+{
+ int status = -1;
+ const char *library_file;
+ void *library_handle;
library_file = (*env)->GetStringUTFChars(env, library, NULL);
library_handle = dlopen(library_file, RTLD_GLOBAL);
@@ -853,10 +873,6 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls,
}
(*env)->ReleaseStringUTFChars(env, library, library_file);
- /* This is a Java thread, it doesn't need to be Detached from the JVM.
- * Set to mThreadKey value to NULL not to call pthread_create destructor 'Android_JNI_ThreadDestroyed' */
- Android_JNI_SetEnv(NULL);
-
/* Do not issue an exit or the whole application will terminate instead of just the SDL thread */
/* exit(status); */