From 2c9dcfa00468c349375b63b92c55d161eee2289d Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 2 Feb 2018 15:20:51 +0200 Subject: Load Qt libs from Qt thread [ChangeLog][Android] The application and dependent Qt libraries are now loaded on the same thread as main() is run on, ensuring that global static initializers, constructor functions, and main() are all run on the same thread. The same applies during application shutdown, for destructors of global objects, and destructor functions. Change-Id: Id4bfece1ed2a0532ed2e8fb7d8ffd6e55d5a10dc Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/plugins/platforms/android/androidjnimain.cpp | 107 +++++++++++------------ 1 file changed, 52 insertions(+), 55 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 2bdd49dc50..13d41bea99 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -59,6 +59,7 @@ #include "qandroideventdispatcher.h" #include +#include #include #include #include @@ -99,7 +100,6 @@ extern "C" typedef int (*Main)(int, char **); //use the standard main method to static Main m_main = nullptr; static void *m_mainLibraryHnd = nullptr; static QList m_applicationParams; -pthread_t m_qtAppThread = 0; static sem_t m_exitSemaphore, m_terminateSemaphore; QHash m_surfaces; @@ -441,57 +441,10 @@ namespace QtAndroid } // namespace QtAndroid -static jboolean startQtAndroidPlugin(JNIEnv* /*env*/, jobject /*object*//*, jobject applicationAssetManager*/) +static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString, jstring environmentString) { m_androidPlatformIntegration = nullptr; m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler(); - return true; -} - -static void *startMainMethod(void */*data*/) -{ - { - JNIEnv* env = nullptr; - JavaVMAttachArgs args; - args.version = JNI_VERSION_1_6; - args.name = "QtMainThread"; - args.group = NULL; - JavaVM *vm = QtAndroidPrivate::javaVM(); - if (vm != 0) - vm->AttachCurrentThread(&env, &args); - } - - QVarLengthArray params(m_applicationParams.size()); - for (int i = 0; i < m_applicationParams.size(); i++) - params[i] = static_cast(m_applicationParams[i].constData()); - - int ret = m_main(m_applicationParams.length(), const_cast(params.data())); - - if (m_mainLibraryHnd) { - int res = dlclose(m_mainLibraryHnd); - if (res < 0) - qWarning() << "dlclose failed:" << dlerror(); - } - - if (m_applicationClass) - QJNIObjectPrivate::callStaticMethod(m_applicationClass, "quitApp", "()V"); - - // All attached threads should be detached before returning from this function. - JavaVM *vm = QtAndroidPrivate::javaVM(); - if (vm != 0) - vm->DetachCurrentThread(); - - sem_post(&m_terminateSemaphore); - sem_wait(&m_exitSemaphore); - sem_destroy(&m_exitSemaphore); - - // We must call exit() to ensure that all global objects will be destructed - exit(ret); - return 0; -} - -static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring paramsString, jstring environmentString) -{ m_mainLibraryHnd = nullptr; { // Set env. vars const char *nativeString = env->GetStringUTFChars(environmentString, 0); @@ -540,14 +493,54 @@ static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring para if (sem_init(&m_terminateSemaphore, 0, 0) == -1) return false; - jboolean res = pthread_create(&m_qtAppThread, nullptr, startMainMethod, nullptr) == 0; + return true; +} +static void waitForServiceSetup(JNIEnv *env, jclass /*clazz*/) +{ + Q_UNUSED(env); // The service must wait until the QCoreApplication starts otherwise onBind will be // called too early if (m_serviceObject) QtAndroidPrivate::waitForServiceSetup(); +} + +static jboolean startQtApplication(JNIEnv */*env*/, jclass /*clazz*/) +{ + { + JNIEnv* env = nullptr; + JavaVMAttachArgs args; + args.version = JNI_VERSION_1_6; + args.name = "QtMainThread"; + args.group = NULL; + JavaVM *vm = QtAndroidPrivate::javaVM(); + if (vm != 0) + vm->AttachCurrentThread(&env, &args); + } + + QVarLengthArray params(m_applicationParams.size()); + for (int i = 0; i < m_applicationParams.size(); i++) + params[i] = static_cast(m_applicationParams[i].constData()); + + int ret = m_main(m_applicationParams.length(), const_cast(params.data())); + + if (m_mainLibraryHnd) { + int res = dlclose(m_mainLibraryHnd); + if (res < 0) + qWarning() << "dlclose failed:" << dlerror(); + } - return res; + if (m_applicationClass) { + qWarning("exit app 0"); + QJNIObjectPrivate::callStaticMethod(m_applicationClass, "quitApp", "()V"); + } + + sem_post(&m_terminateSemaphore); + sem_wait(&m_exitSemaphore); + sem_destroy(&m_exitSemaphore); + + // We must call exit() to ensure that all global objects will be destructed + exit(ret); } static void quitQtCoreApplication(JNIEnv *env, jclass /*clazz*/) @@ -593,7 +586,6 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) if (!QAndroidEventDispatcherStopper::instance()->stopped()) { sem_post(&m_exitSemaphore); - pthread_join(m_qtAppThread, nullptr); } } @@ -758,11 +750,12 @@ static jobject onBind(JNIEnv */*env*/, jclass /*cls*/, jobject intent) } static JNINativeMethod methods[] = { - {"startQtAndroidPlugin", "()Z", (void *)startQtAndroidPlugin}, - {"startQtApplication", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)startQtApplication}, + {"startQtAndroidPlugin", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)startQtAndroidPlugin}, + {"startQtApplication", "()V", (void *)startQtApplication}, {"quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin}, {"quitQtCoreApplication", "()V", (void *)quitQtCoreApplication}, {"terminateQt", "()V", (void *)terminateQt}, + {"waitForServiceSetup", "()V", (void *)waitForServiceSetup}, {"setDisplayMetrics", "(IIIIDDDD)V", (void *)setDisplayMetrics}, {"setSurface", "(ILjava/lang/Object;II)V", (void *)setSurface}, {"updateWindow", "()V", (void *)updateWindow}, @@ -884,7 +877,6 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) void *venv; } UnionJNIEnvToVoid; - __android_log_print(ANDROID_LOG_INFO, "Qt", "qt start"); UnionJNIEnvToVoid uenv; uenv.venv = nullptr; m_javaVM = nullptr; @@ -906,5 +898,10 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); m_javaVM = vm; + // attach qt main thread data to this thread + QObject threadSetter; + if (threadSetter.thread()) + threadSetter.thread()->setObjectName("QtMainLoopThread"); + __android_log_print(ANDROID_LOG_INFO, "Qt", "qt started"); return JNI_VERSION_1_4; } -- cgit v1.2.3