From cf1e7ce35deb3ccaf3ee5e9897f6ac48586f1dfe Mon Sep 17 00:00:00 2001 From: f321x Date: Wed, 28 Oct 2026 10:18:46 +0100 Subject: [PATCH 1/2] qt bootstrap: provide the JNIEnv getter pyjnius and android need For every bootstrap that is not sdl2/sdl3, the android recipe defines SDL_ANDROID_GetJNIEnv as WebView_AndroidGetJNIEnv and pyjnius' genericndkbuild_jnienv_getter.patch makes jnius call the same symbol. Both then link against the bootstrap's main library: the android recipe via ANDROID_MAIN_LIB, pyjnius via PYJNIUS_ANDROID_LIBMAIN. The qt bootstrap builds libmain_.so from start.c alone, so nothing defines that symbol and the references to it from android._android and jnius cannot be resolved. pyjniusjni.c, which defines it, was duplicated byte for byte in the webview and service_only bootstraps. Move it next to start.c in common/ and list it in the qt bootstrap's LOCAL_SRC_FILES. sdl2 and sdl3 do not list it in their own Android.mk, so they never compile it and keep getting the JNIEnv from SDL. Qt reaches libmain_.so through QtLoader.loadMainLibrary(), which calls System.load()/System.loadLibrary(), so the JNI_OnLoad in pyjniusjni.c runs and caches the JavaVM. --- .../build/jni/application/src/pyjniusjni.c | 0 .../qt/build/jni/application/src/Android.mk | 2 +- .../build/jni/application/src/pyjniusjni.c | 103 ------------------ 3 files changed, 1 insertion(+), 104 deletions(-) rename pythonforandroid/bootstraps/{service_only => common}/build/jni/application/src/pyjniusjni.c (100%) delete mode 100644 pythonforandroid/bootstraps/webview/build/jni/application/src/pyjniusjni.c diff --git a/pythonforandroid/bootstraps/service_only/build/jni/application/src/pyjniusjni.c b/pythonforandroid/bootstraps/common/build/jni/application/src/pyjniusjni.c similarity index 100% rename from pythonforandroid/bootstraps/service_only/build/jni/application/src/pyjniusjni.c rename to pythonforandroid/bootstraps/common/build/jni/application/src/pyjniusjni.c diff --git a/pythonforandroid/bootstraps/qt/build/jni/application/src/Android.mk b/pythonforandroid/bootstraps/qt/build/jni/application/src/Android.mk index aebe3f623b..bf46570a08 100644 --- a/pythonforandroid/bootstraps/qt/build/jni/application/src/Android.mk +++ b/pythonforandroid/bootstraps/qt/build/jni/application/src/Android.mk @@ -5,7 +5,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := main_$(PREFERRED_ABI) # Add your application source files here... -LOCAL_SRC_FILES := start.c +LOCAL_SRC_FILES := start.c pyjniusjni.c LOCAL_CFLAGS += -I$(PYTHON_INCLUDE_ROOT) $(EXTRA_CFLAGS) diff --git a/pythonforandroid/bootstraps/webview/build/jni/application/src/pyjniusjni.c b/pythonforandroid/bootstraps/webview/build/jni/application/src/pyjniusjni.c deleted file mode 100644 index d67972a4db..0000000000 --- a/pythonforandroid/bootstraps/webview/build/jni/application/src/pyjniusjni.c +++ /dev/null @@ -1,103 +0,0 @@ - -#include -#include - -#define LOGI(...) do {} while (0) -#define LOGE(...) do {} while (0) - -#include "android/log.h" - -/* These JNI management functions are taken from SDL2, but modified to refer to pyjnius */ - -/* #define LOG(n, x) __android_log_write(ANDROID_LOG_INFO, (n), (x)) */ -/* #define LOGP(x) LOG("python", (x)) */ -#define LOG_TAG "Python_android" -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) - - -/* Function headers */ -JNIEnv* Android_JNI_GetEnv(void); -static void Android_JNI_ThreadDestroyed(void*); - -static pthread_key_t mThreadKey; -static JavaVM* mJavaVM; - -int Android_JNI_SetupThread(void) -{ - Android_JNI_GetEnv(); - return 1; -} - -/* Library init */ -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) -{ - JNIEnv *env; - mJavaVM = vm; - LOGI("JNI_OnLoad called"); - if ((*mJavaVM)->GetEnv(mJavaVM, (void**) &env, JNI_VERSION_1_4) != JNI_OK) { - LOGE("Failed to get the environment using GetEnv()"); - return -1; - } - /* - * Create mThreadKey so we can keep track of the JNIEnv assigned to each thread - * Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this - */ - if (pthread_key_create(&mThreadKey, Android_JNI_ThreadDestroyed) != 0) { - - __android_log_print(ANDROID_LOG_ERROR, "pyjniusjni", "Error initializing pthread key"); - } - Android_JNI_SetupThread(); - - return JNI_VERSION_1_4; -} - -JNIEnv* Android_JNI_GetEnv(void) -{ - /* From http://developer.android.com/guide/practices/jni.html - * All threads are Linux threads, scheduled by the kernel. - * They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then - * attached to the JavaVM. For example, a thread started with pthread_create can be attached with the - * JNI AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a thread is attached, it has no JNIEnv, - * and cannot make JNI calls. - * Attaching a natively-created thread causes a java.lang.Thread object to be constructed and added to the "main" - * ThreadGroup, making it visible to the debugger. Calling AttachCurrentThread on an already-attached thread - * is a no-op. - * Note: You can call this function any number of times for the same thread, there's no harm in it - */ - - JNIEnv *env; - int status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env, NULL); - if(status < 0) { - LOGE("failed to attach current thread"); - return 0; - } - - /* From http://developer.android.com/guide/practices/jni.html - * Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward, - * in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be - * called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific - * to store the JNIEnv in thread-local-storage; that way it'll be passed into your destructor as the argument.) - * Note: The destructor is not called unless the stored value is != NULL - * Note: You can call this function any number of times for the same thread, there's no harm in it - * (except for some lost CPU cycles) - */ - pthread_setspecific(mThreadKey, (void*) env); - - return env; -} - -static void Android_JNI_ThreadDestroyed(void* value) -{ - /* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */ - JNIEnv *env = (JNIEnv*) value; - if (env != NULL) { - (*mJavaVM)->DetachCurrentThread(mJavaVM); - pthread_setspecific(mThreadKey, NULL); - } -} - -void *WebView_AndroidGetJNIEnv() -{ - return Android_JNI_GetEnv(); -} From bb0b394bafc1c1f950f263d8625996e8461a1522 Mon Sep 17 00:00:00 2001 From: f321x Date: Wed, 28 Oct 2026 10:22:14 +0100 Subject: [PATCH 2/2] bootstraps: drop the dead Android_static.mk files Nothing in the tree reads them. ndk-build only ever includes files named Android.mk: the jni/Android.mk and jni/application/Android.mk entry points use $(call all-subdir-makefiles), which globs */Android.mk, and no makefile includes Android_static.mk by name. They are leftovers from the SDL android-project template, and they could not work as written anyway: webview's links an SDL2_static module into a bootstrap that builds no SDL, sdl3's asks for an SDL3_static module that the SDL3 sources do not define, webview and service_only name a YourSourceHere.c that does not exist, and four of the five end in the mangled $(call import-module,SDL)LOCAL_PATH := $(call my-dir) that SDL's own template already shipped with. Each new bootstrap has been carrying the file forward since, most recently qt and sdl3. --- .../qt/build/jni/application/src/Android_static.mk | 9 --------- .../build/jni/application/src/Android_static.mk | 12 ------------ .../build/jni/application/src/Android_static.mk | 13 ------------- .../build/jni/application/src/Android_static.mk | 10 ---------- .../build/jni/application/src/Android_static.mk | 12 ------------ 5 files changed, 56 deletions(-) delete mode 100644 pythonforandroid/bootstraps/qt/build/jni/application/src/Android_static.mk delete mode 100644 pythonforandroid/bootstraps/sdl2/build/jni/application/src/Android_static.mk delete mode 100644 pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android_static.mk delete mode 100644 pythonforandroid/bootstraps/service_only/build/jni/application/src/Android_static.mk delete mode 100644 pythonforandroid/bootstraps/webview/build/jni/application/src/Android_static.mk diff --git a/pythonforandroid/bootstraps/qt/build/jni/application/src/Android_static.mk b/pythonforandroid/bootstraps/qt/build/jni/application/src/Android_static.mk deleted file mode 100644 index 1bb58cb76d..0000000000 --- a/pythonforandroid/bootstraps/qt/build/jni/application/src/Android_static.mk +++ /dev/null @@ -1,9 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := main_$(PREFERRED_ABI) - -LOCAL_SRC_FILES := start.c - -include $(BUILD_SHARED_LIBRARY) diff --git a/pythonforandroid/bootstraps/sdl2/build/jni/application/src/Android_static.mk b/pythonforandroid/bootstraps/sdl2/build/jni/application/src/Android_static.mk deleted file mode 100644 index 517660be2a..0000000000 --- a/pythonforandroid/bootstraps/sdl2/build/jni/application/src/Android_static.mk +++ /dev/null @@ -1,12 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := main - -LOCAL_SRC_FILES := start.c - -LOCAL_STATIC_LIBRARIES := SDL2_static - -include $(BUILD_SHARED_LIBRARY) -$(call import-module,SDL)LOCAL_PATH := $(call my-dir) diff --git a/pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android_static.mk b/pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android_static.mk deleted file mode 100644 index f4ff2462e6..0000000000 --- a/pythonforandroid/bootstraps/sdl3/build/jni/application/src/Android_static.mk +++ /dev/null @@ -1,13 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := main - -LOCAL_SRC_FILES := start.c - -LOCAL_STATIC_LIBRARIES := SDL3_static - - -include $(BUILD_SHARED_LIBRARY) -$(call import-module,SDL)LOCAL_PATH := $(call my-dir) diff --git a/pythonforandroid/bootstraps/service_only/build/jni/application/src/Android_static.mk b/pythonforandroid/bootstraps/service_only/build/jni/application/src/Android_static.mk deleted file mode 100644 index 2de278ee00..0000000000 --- a/pythonforandroid/bootstraps/service_only/build/jni/application/src/Android_static.mk +++ /dev/null @@ -1,10 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := main - -LOCAL_SRC_FILES := YourSourceHere.c - -include $(BUILD_SHARED_LIBRARY) -$(call import-module,SDL)LOCAL_PATH := $(call my-dir) diff --git a/pythonforandroid/bootstraps/webview/build/jni/application/src/Android_static.mk b/pythonforandroid/bootstraps/webview/build/jni/application/src/Android_static.mk deleted file mode 100644 index faed669c0e..0000000000 --- a/pythonforandroid/bootstraps/webview/build/jni/application/src/Android_static.mk +++ /dev/null @@ -1,12 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := main - -LOCAL_SRC_FILES := YourSourceHere.c - -LOCAL_STATIC_LIBRARIES := SDL2_static - -include $(BUILD_SHARED_LIBRARY) -$(call import-module,SDL)LOCAL_PATH := $(call my-dir)