Android: replace QtAndroid::activity/service with QtAndroidPrivate

There's no need for both, and QtAndroidPrivate is a documented namespace.
Replace all calls to QtAndroid::activity/service with QtAndroidPrivate
equivalents, and drop the QtAndroid version. Since we no longer store a
global copy of the activity and service, we can drop the reference right
away.

This comes with a bit of overhead - QtAndroid::activity returned a copy
of a global static QJniObject (62cb5589b3723fe8162e190cd54d9c78929b98d2,
after which declared QtJniTypes became QJniObjects), while
QtAndroidPrivate::activity returns a newly created QtJniTypes::Activity
on each call.

This however makes it also safer, as the QJniObject is then associated
with the calling thread's JNI environment, and we can optimize critical
code paths where it's safe to do so later. Also, QtAndroid's activity
object was never updated, while QtAndroidPrivate's activity is updated
in the updateNativeActivity native method.

Change-Id: I36c5b504eac52d9e28b4c6b265daab8fedc877e2
Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
This commit is contained in:
Volker Hilsheimer 2023-10-26 16:30:36 +02:00
parent d44aae1358
commit 703614f03b
8 changed files with 49 additions and 51 deletions

View File

@ -253,12 +253,24 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
return JNI_OK; return JNI_OK;
} }
Q_CORE_EXPORT jobject qt_androidActivity()
{
QReadLocker locker(g_updateMutex());
return g_jActivity;
}
QtJniTypes::Activity QtAndroidPrivate::activity() QtJniTypes::Activity QtAndroidPrivate::activity()
{ {
QReadLocker locker(g_updateMutex()); QReadLocker locker(g_updateMutex());
return g_jActivity; return g_jActivity;
} }
Q_CORE_EXPORT jobject qt_androidService()
{
return g_jService;
}
QtJniTypes::Service QtAndroidPrivate::service() QtJniTypes::Service QtAndroidPrivate::service()
{ {
return g_jService; return g_jService;

View File

@ -44,9 +44,7 @@ static jmethodID m_loadClassMethodID = nullptr;
static AAssetManager *m_assetManager = nullptr; static AAssetManager *m_assetManager = nullptr;
static jobject m_assets = nullptr; static jobject m_assets = nullptr;
static jobject m_resourcesObj = nullptr; static jobject m_resourcesObj = nullptr;
static QtJniTypes::Activity m_activityObject = nullptr;
static jmethodID m_createSurfaceMethodID = nullptr; static jmethodID m_createSurfaceMethodID = nullptr;
static QtJniTypes::Service m_serviceObject = nullptr;
static jmethodID m_setSurfaceGeometryMethodID = nullptr; static jmethodID m_setSurfaceGeometryMethodID = nullptr;
static jmethodID m_destroySurfaceMethodID = nullptr; static jmethodID m_destroySurfaceMethodID = nullptr;
@ -160,16 +158,6 @@ namespace QtAndroid
return m_applicationClass; return m_applicationClass;
} }
QtJniTypes::Activity activity()
{
return m_activityObject;
}
QtJniTypes::Service service()
{
return m_serviceObject;
}
void setSystemUiVisibility(SystemUiVisibility uiVisibility) void setSystemUiVisibility(SystemUiVisibility uiVisibility)
{ {
QJniObject::callStaticMethod<void>(m_applicationClass, "setSystemUiVisibility", "(I)V", jint(uiVisibility)); QJniObject::callStaticMethod<void>(m_applicationClass, "setSystemUiVisibility", "(I)V", jint(uiVisibility));
@ -496,7 +484,7 @@ static void waitForServiceSetup(JNIEnv *env, jclass /*clazz*/)
Q_UNUSED(env); Q_UNUSED(env);
// The service must wait until the QCoreApplication starts otherwise onBind will be // The service must wait until the QCoreApplication starts otherwise onBind will be
// called too early // called too early
if (m_serviceObject) if (QtAndroidPrivate::service())
QtAndroidPrivate::waitForServiceSetup(); QtAndroidPrivate::waitForServiceSetup();
} }
@ -867,28 +855,24 @@ static int registerNatives(JNIEnv *env)
jmethodID methodID; jmethodID methodID;
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;"); GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID); jobject contextObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "service", "()Landroid/app/Service;"); if (!contextObject) {
jobject serviceObject = env->CallStaticObjectMethod(m_applicationClass, methodID); GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "service", "()Landroid/app/Service;");
contextObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
}
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;"); GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;");
m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID)); m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID));
clazz = env->GetObjectClass(m_classLoaderObject); clazz = env->GetObjectClass(m_classLoaderObject);
GET_AND_CHECK_METHOD(m_loadClassMethodID, clazz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); GET_AND_CHECK_METHOD(m_loadClassMethodID, clazz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
if (serviceObject)
m_serviceObject = serviceObject; // m_serviceObject creates and manages as global ref
if (activityObject) if (contextObject) {
m_activityObject = activityObject; // m_activityObject creates and manages as global ref
jobject object = activityObject ? activityObject : serviceObject;
if (object) {
FIND_AND_CHECK_CLASS("android/content/ContextWrapper"); FIND_AND_CHECK_CLASS("android/content/ContextWrapper");
GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;"); GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;");
m_assets = env->NewGlobalRef(env->CallObjectMethod(object, methodID)); m_assets = env->NewGlobalRef(env->CallObjectMethod(contextObject, methodID));
m_assetManager = AAssetManager_fromJava(env, m_assets); m_assetManager = AAssetManager_fromJava(env, m_assets);
GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;"); GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(object, methodID)); m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(contextObject, methodID));
FIND_AND_CHECK_CLASS("android/graphics/Bitmap"); FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz)); m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
@ -907,6 +891,8 @@ static int registerNatives(JNIEnv *env)
m_bitmapDrawableClass, m_bitmapDrawableClass,
"<init>", "<init>",
"(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V"); "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
env->DeleteLocalRef(contextObject);
} }
return JNI_TRUE; return JNI_TRUE;

View File

@ -50,8 +50,6 @@ namespace QtAndroid
jobject assets(); jobject assets();
AAssetManager *assetManager(); AAssetManager *assetManager();
jclass applicationClass(); jclass applicationClass();
QtJniTypes::Activity activity();
QtJniTypes::Service service();
// Keep synchronized with flags in ActivityDelegate.java // Keep synchronized with flags in ActivityDelegate.java
enum SystemUiVisibility { enum SystemUiVisibility {

View File

@ -19,7 +19,7 @@ static jclass g_messageDialogHelperClass = nullptr;
QAndroidPlatformMessageDialogHelper::QAndroidPlatformMessageDialogHelper() QAndroidPlatformMessageDialogHelper::QAndroidPlatformMessageDialogHelper()
: m_javaMessageDialog(g_messageDialogHelperClass, "(Landroid/app/Activity;)V", : m_javaMessageDialog(g_messageDialogHelperClass, "(Landroid/app/Activity;)V",
static_cast<jobject>(QtAndroid::activity())) static_cast<jobject>(QtAndroidPrivate::activity()))
{ {
} }

View File

@ -25,7 +25,7 @@ const char JniIntentClass[] = "android/content/Intent";
QAndroidPlatformFileDialogHelper::QAndroidPlatformFileDialogHelper() QAndroidPlatformFileDialogHelper::QAndroidPlatformFileDialogHelper()
: QPlatformFileDialogHelper(), : QPlatformFileDialogHelper(),
m_activity(QtAndroid::activity()) m_activity(QtAndroidPrivate::activity())
{ {
} }

View File

@ -80,10 +80,14 @@ void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteA
{ {
if (resource=="JavaVM") if (resource=="JavaVM")
return QtAndroid::javaVM(); return QtAndroid::javaVM();
if (resource == "QtActivity") if (resource == "QtActivity") {
return QtAndroid::activity(); extern Q_CORE_EXPORT jobject qt_androidActivity();
if (resource == "QtService") return qt_androidActivity();
return QtAndroid::service(); }
if (resource == "QtService") {
extern Q_CORE_EXPORT jobject qt_androidService();
return qt_androidService();
}
if (resource == "AndroidStyleData") { if (resource == "AndroidStyleData") {
if (m_androidStyle) { if (m_androidStyle) {
if (m_androidStyle->m_styleData.isEmpty()) if (m_androidStyle->m_styleData.isEmpty())
@ -227,9 +231,9 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
m_accessibility = new QAndroidPlatformAccessibility(); m_accessibility = new QAndroidPlatformAccessibility();
#endif // QT_CONFIG(accessibility) #endif // QT_CONFIG(accessibility)
QJniObject javaActivity(QtAndroid::activity()); QJniObject javaActivity = QtAndroidPrivate::activity();
if (!javaActivity.isValid()) if (!javaActivity.isValid())
javaActivity = QtAndroid::service(); javaActivity = QtAndroidPrivate::service();
if (javaActivity.isValid()) { if (javaActivity.isValid()) {
QJniObject resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;"); QJniObject resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
@ -316,11 +320,11 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
switch (cap) { switch (cap) {
case ApplicationState: return true; case ApplicationState: return true;
case ThreadedPixmaps: return true; case ThreadedPixmaps: return true;
case NativeWidgets: return QtAndroid::activity(); case NativeWidgets: return QtAndroidPrivate::activity();
case OpenGL: return QtAndroid::activity(); case OpenGL: return QtAndroidPrivate::activity();
case ForeignWindows: return QtAndroid::activity(); case ForeignWindows: return QtAndroidPrivate::activity();
case ThreadedOpenGL: return !needsBasicRenderloopWorkaround() && QtAndroid::activity(); case ThreadedOpenGL: return !needsBasicRenderloopWorkaround() && QtAndroidPrivate::activity();
case RasterGLSurface: return QtAndroid::activity(); case RasterGLSurface: return QtAndroidPrivate::activity();
case TopStackedNativeChildWindows: return false; case TopStackedNativeChildWindows: return false;
case MaximizeUsingFullscreenGeometry: return true; case MaximizeUsingFullscreenGeometry: return true;
default: default:
@ -330,7 +334,7 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(QWindow *window) const QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(QWindow *window) const
{ {
if (!QtAndroid::activity()) if (!QtAndroidPrivate::activity())
return nullptr; return nullptr;
return new QAndroidPlatformBackingStore(window); return new QAndroidPlatformBackingStore(window);
@ -338,7 +342,7 @@ QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(Q
QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{ {
if (!QtAndroid::activity()) if (!QtAndroidPrivate::activity())
return nullptr; return nullptr;
QSurfaceFormat format(context->format()); QSurfaceFormat format(context->format());
format.setAlphaBufferSize(8); format.setAlphaBufferSize(8);
@ -356,7 +360,7 @@ QOpenGLContext *QAndroidPlatformIntegration::createOpenGLContext(EGLContext cont
QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
{ {
if (!QtAndroid::activity()) if (!QtAndroidPrivate::activity())
return nullptr; return nullptr;
QSurfaceFormat format(surface->requestedFormat()); QSurfaceFormat format(surface->requestedFormat());
@ -370,7 +374,7 @@ QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenS
QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWindow *nativeSurface) const QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWindow *nativeSurface) const
{ {
if (!QtAndroid::activity() || !nativeSurface) if (!QtAndroidPrivate::activity() || !nativeSurface)
return nullptr; return nullptr;
auto *surface = new QOffscreenSurface; auto *surface = new QOffscreenSurface;
@ -381,7 +385,7 @@ QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWi
QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
{ {
if (!QtAndroid::activity()) if (!QtAndroidPrivate::activity())
return nullptr; return nullptr;
#if QT_CONFIG(vulkan) #if QT_CONFIG(vulkan)

View File

@ -368,7 +368,7 @@ int QAndroidPlatformScreen::rasterSurfaces()
void QAndroidPlatformScreen::doRedraw(QImage* screenGrabImage) void QAndroidPlatformScreen::doRedraw(QImage* screenGrabImage)
{ {
PROFILE_SCOPE; PROFILE_SCOPE;
if (!QtAndroid::activity()) if (!QtAndroidPrivate::activity())
return; return;
if (m_dirtyRect.isEmpty()) if (m_dirtyRect.isEmpty())

View File

@ -21,11 +21,9 @@ void QAndroidSystemLocale::getLocaleFromJava() const
QWriteLocker locker(&m_lock); QWriteLocker locker(&m_lock);
QJniObject javaLocaleObject; QJniObject javaLocaleObject;
QJniObject javaActivity(QtAndroid::activity()); const QJniObject javaContext = QtAndroidPrivate::context();
if (!javaActivity.isValid()) if (javaContext.isValid()) {
javaActivity = QtAndroid::service(); QJniObject resources = javaContext.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
if (javaActivity.isValid()) {
QJniObject resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
QJniObject configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;"); QJniObject configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
javaLocaleObject = configuration.getObjectField("locale", "Ljava/util/Locale;"); javaLocaleObject = configuration.getObjectField("locale", "Ljava/util/Locale;");