From 3ec607313b635aca148146a994bd3181dddb6522 Mon Sep 17 00:00:00 2001 From: Andrew Shkrob Date: Tue, 14 Jan 2025 21:10:53 +0100 Subject: [PATCH] [android] Refactor cpp-java ui thread forwarding Signed-off-by: Andrew Shkrob --- android/app/src/main/cpp/CMakeLists.txt | 1 + .../cpp/app/organicmaps/MwmApplication.cpp | 22 +++++----------- .../organicmaps/platform/AndroidPlatform.cpp | 13 +++++++--- .../organicmaps/platform/AndroidPlatform.hpp | 3 +++ .../app/organicmaps/platform/GuiThread.cpp | 14 +++++----- .../app/organicmaps/platform/GuiThread.hpp | 6 ++--- .../cpp/app/organicmaps/util/UiThread.cpp | 12 +++++++++ .../java/app/organicmaps/MwmApplication.java | 26 ++++--------------- .../util/concurrency/UiThread.java | 14 +++++++++- 9 files changed, 60 insertions(+), 51 deletions(-) create mode 100644 android/app/src/main/cpp/app/organicmaps/util/UiThread.cpp diff --git a/android/app/src/main/cpp/CMakeLists.txt b/android/app/src/main/cpp/CMakeLists.txt index f741fbfeb6..91a173d7b1 100644 --- a/android/app/src/main/cpp/CMakeLists.txt +++ b/android/app/src/main/cpp/CMakeLists.txt @@ -66,6 +66,7 @@ set(SRC app/organicmaps/util/LogsManager.cpp app/organicmaps/util/NetworkPolicy.cpp app/organicmaps/util/StringUtils.cpp + app/organicmaps/util/UiThread.cpp app/organicmaps/vulkan/android_vulkan_context_factory.cpp ) diff --git a/android/app/src/main/cpp/app/organicmaps/MwmApplication.cpp b/android/app/src/main/cpp/app/organicmaps/MwmApplication.cpp index d7d24e921d..88f38cfb0c 100644 --- a/android/app/src/main/cpp/app/organicmaps/MwmApplication.cpp +++ b/android/app/src/main/cpp/app/organicmaps/MwmApplication.cpp @@ -1,6 +1,5 @@ #include "app/organicmaps/Framework.hpp" -#include "app/organicmaps/platform/GuiThread.hpp" #include "app/organicmaps/platform/AndroidPlatform.hpp" #include "app/organicmaps/core/jni_helper.hpp" @@ -14,16 +13,16 @@ extern "C" android::Platform::Instance().SetSettingsDir(jni::ToNativeString(env, settingsPath)); } - // void nativeInitPlatform(String apkPath, String storagePath, String privatePath, String tmpPath, + // static void nativeInitPlatform(Context context, String apkPath, String storagePath, String privatePath, String tmpPath, // String flavorName, String buildType, boolean isTablet); JNIEXPORT void JNICALL - Java_app_organicmaps_MwmApplication_nativeInitPlatform(JNIEnv * env, jobject thiz, - jstring apkPath, jstring writablePath, - jstring privatePath, jstring tmpPath, - jstring flavorName, jstring buildType, - jboolean isTablet) + Java_app_organicmaps_MwmApplication_nativeInitPlatform(JNIEnv * env, jclass clazz, jobject context, + jstring apkPath, jstring writablePath, + jstring privatePath, jstring tmpPath, + jstring flavorName, jstring buildType, + jboolean isTablet) { - android::Platform::Instance().Initialize(env, thiz, apkPath, writablePath, privatePath, tmpPath, + android::Platform::Instance().Initialize(env, context, apkPath, writablePath, privatePath, tmpPath, flavorName, buildType, isTablet); } @@ -42,13 +41,6 @@ extern "C" } } - // static void nativeProcessTask(long taskPointer); - JNIEXPORT void JNICALL - Java_app_organicmaps_MwmApplication_nativeProcessTask(JNIEnv * env, jclass clazz, jlong taskPointer) - { - android::GuiThread::ProcessTask(taskPointer); - } - // static void nativeAddLocalization(String name, String value); JNIEXPORT void JNICALL Java_app_organicmaps_MwmApplication_nativeAddLocalization(JNIEnv * env, jclass clazz, jstring name, jstring value) diff --git a/android/app/src/main/cpp/app/organicmaps/platform/AndroidPlatform.cpp b/android/app/src/main/cpp/app/organicmaps/platform/AndroidPlatform.cpp index 2fc6eb7bba..b15c6d9748 100644 --- a/android/app/src/main/cpp/app/organicmaps/platform/AndroidPlatform.cpp +++ b/android/app/src/main/cpp/app/organicmaps/platform/AndroidPlatform.cpp @@ -130,11 +130,18 @@ platform::NetworkPolicy GetCurrentNetworkPolicy() namespace android { -void Platform::Initialize(JNIEnv * env, jobject functorProcessObject, jstring apkPath, +Platform::~Platform() +{ + JNIEnv *env = jni::GetEnv(); + env->DeleteGlobalRef(m_context); +} + +void Platform::Initialize(JNIEnv * env, jobject context, jstring apkPath, jstring writablePath, jstring privatePath, jstring tmpPath, jstring flavorName, jstring buildType, bool isTablet) { - m_guiThread = std::make_unique(functorProcessObject); + m_context = env->NewGlobalRef(context); + m_guiThread = std::make_unique(); std::string const flavor = jni::ToNativeString(env, flavorName); std::string const build = jni::ToNativeString(env, buildType); @@ -182,7 +189,7 @@ Platform & Platform::Instance() jobject Platform::GetContext() const { - return static_cast(m_guiThread.get())->GetObject(); + return m_context; } void Platform::AndroidSecureStorage::Init(JNIEnv * env) diff --git a/android/app/src/main/cpp/app/organicmaps/platform/AndroidPlatform.hpp b/android/app/src/main/cpp/app/organicmaps/platform/AndroidPlatform.hpp index 657e1367e2..4a4b34f273 100644 --- a/android/app/src/main/cpp/app/organicmaps/platform/AndroidPlatform.hpp +++ b/android/app/src/main/cpp/app/organicmaps/platform/AndroidPlatform.hpp @@ -17,6 +17,8 @@ namespace android class Platform : public ::Platform { public: + ~Platform() override; + void Initialize(JNIEnv * env, jobject functorProcessObject, jstring apkPath, jstring writablePath, jstring privatePath, jstring tmpPath, jstring flavorName, jstring buildType, bool isTablet); @@ -49,5 +51,6 @@ public: private: AndroidSecureStorage m_secureStorage; + jobject m_context; }; } // namespace android diff --git a/android/app/src/main/cpp/app/organicmaps/platform/GuiThread.cpp b/android/app/src/main/cpp/app/organicmaps/platform/GuiThread.cpp index af87b05bc6..2cac1df33f 100644 --- a/android/app/src/main/cpp/app/organicmaps/platform/GuiThread.cpp +++ b/android/app/src/main/cpp/app/organicmaps/platform/GuiThread.cpp @@ -6,21 +6,21 @@ namespace android { -GuiThread::GuiThread(jobject processObject) +GuiThread::GuiThread() { JNIEnv * env = jni::GetEnv(); - m_object = env->NewGlobalRef(processObject); - ASSERT(m_object, ()); + m_class = GetGlobalClassRef(env, "app/organicmaps/util/concurrency/UiThread"); + ASSERT(m_class, ()); - m_method = env->GetMethodID(env->GetObjectClass(m_object), "forwardToMainThread", "(J)V"); + m_method = env->GetStaticMethodID(m_class, "forwardToMainThread", "(J)V"); ASSERT(m_method, ()); } GuiThread::~GuiThread() { JNIEnv * env = jni::GetEnv(); - env->DeleteGlobalRef(m_object); + env->DeleteGlobalRef(m_class); } // static @@ -34,7 +34,7 @@ base::TaskLoop::PushResult GuiThread::Push(Task && task) { // Pointer will be deleted in ProcessTask. auto t = new Task(std::move(task)); - jni::GetEnv()->CallVoidMethod(m_object, m_method, reinterpret_cast(t)); + jni::GetEnv()->CallStaticVoidMethod(m_class, m_method, reinterpret_cast(t)); return {true, kNoId}; } @@ -42,7 +42,7 @@ base::TaskLoop::PushResult GuiThread::Push(Task const & task) { // Pointer will be deleted in ProcessTask. auto t = new Task(task); - jni::GetEnv()->CallVoidMethod(m_object, m_method, reinterpret_cast(t)); + jni::GetEnv()->CallStaticVoidMethod(m_class, m_method, reinterpret_cast(t)); return {true, kNoId}; } } // namespace android diff --git a/android/app/src/main/cpp/app/organicmaps/platform/GuiThread.hpp b/android/app/src/main/cpp/app/organicmaps/platform/GuiThread.hpp index e49ed06325..b764f9ea8b 100644 --- a/android/app/src/main/cpp/app/organicmaps/platform/GuiThread.hpp +++ b/android/app/src/main/cpp/app/organicmaps/platform/GuiThread.hpp @@ -9,7 +9,7 @@ namespace android class GuiThread : public base::TaskLoop { public: - explicit GuiThread(jobject processObject); + GuiThread(); ~GuiThread() override; static void ProcessTask(jlong task); @@ -18,10 +18,8 @@ public: PushResult Push(Task && task) override; PushResult Push(Task const & task) override; - jobject GetObject() const { return m_object; } - private: - jobject m_object = nullptr; + jclass m_class = nullptr; jmethodID m_method = nullptr; }; } // namespace android diff --git a/android/app/src/main/cpp/app/organicmaps/util/UiThread.cpp b/android/app/src/main/cpp/app/organicmaps/util/UiThread.cpp new file mode 100644 index 0000000000..bd54eec300 --- /dev/null +++ b/android/app/src/main/cpp/app/organicmaps/util/UiThread.cpp @@ -0,0 +1,12 @@ +#include "app/organicmaps/core/jni_helper.hpp" +#include "app/organicmaps/platform/GuiThread.hpp" + +extern "C" +{ +// static void nativeProcessTask(long taskPointer); +JNIEXPORT void JNICALL +Java_app_organicmaps_util_concurrency_UiThread_nativeProcessTask(JNIEnv * env, jclass clazz, jlong taskPointer) +{ + android::GuiThread::ProcessTask(taskPointer); +} +} diff --git a/android/app/src/main/java/app/organicmaps/MwmApplication.java b/android/app/src/main/java/app/organicmaps/MwmApplication.java index 4951e5936a..725a0bca2d 100644 --- a/android/app/src/main/java/app/organicmaps/MwmApplication.java +++ b/android/app/src/main/java/app/organicmaps/MwmApplication.java @@ -7,10 +7,7 @@ import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; @@ -81,8 +78,6 @@ public class MwmApplication extends Application implements Application.ActivityL private volatile boolean mFrameworkInitialized; private volatile boolean mPlatformInitialized; - private Handler mMainLoopHandler; - private final Object mMainQueueToken = new Object(); @NonNull private final MapManager.StorageCallback mStorageCallbacks = new StorageCallbackImpl(); @@ -157,7 +152,6 @@ public class MwmApplication extends Application implements Application.ActivityL Config.init(this); - mMainLoopHandler = new Handler(getMainLooper()); ConnectionState.INSTANCE.initialize(this); DownloaderNotifier.createNotificationChannel(this); @@ -204,7 +198,8 @@ public class MwmApplication extends Application implements Application.ActivityL // external storage is damaged or not available (read-only). createPlatformDirectories(writablePath, privatePath, tempPath); - nativeInitPlatform(apkPath, + nativeInitPlatform(getApplicationContext(), + apkPath, writablePath, privatePath, tempPath, @@ -275,22 +270,11 @@ public class MwmApplication extends Application implements Application.ActivityL System.loadLibrary("organicmaps"); } - // Called from JNI. - @Keep - @SuppressWarnings("unused") - private void forwardToMainThread(final long taskPointer) - { - Message m = Message.obtain(mMainLoopHandler, () -> nativeProcessTask(taskPointer)); - m.obj = mMainQueueToken; - mMainLoopHandler.sendMessage(m); - } - private static native void nativeSetSettingsDir(String settingsPath); - private native void nativeInitPlatform(String apkPath, String writablePath, String privatePath, - String tmpPath, String flavorName, String buildType, - boolean isTablet); + private static native void nativeInitPlatform(Context context, String apkPath, String writablePath, + String privatePath, String tmpPath, String flavorName, + String buildType, boolean isTablet); private static native void nativeInitFramework(@NonNull Runnable onComplete); - private static native void nativeProcessTask(long taskPointer); private static native void nativeAddLocalization(String name, String value); private static native void nativeOnTransit(boolean foreground); diff --git a/android/app/src/main/java/app/organicmaps/util/concurrency/UiThread.java b/android/app/src/main/java/app/organicmaps/util/concurrency/UiThread.java index d1f1d0bf10..21177b1d02 100644 --- a/android/app/src/main/java/app/organicmaps/util/concurrency/UiThread.java +++ b/android/app/src/main/java/app/organicmaps/util/concurrency/UiThread.java @@ -3,6 +3,8 @@ package app.organicmaps.util.concurrency; import android.os.Handler; import android.os.Looper; +import androidx.annotation.Keep; + public class UiThread { private static final Handler sUiHandler = new Handler(Looper.getMainLooper()); @@ -38,7 +40,7 @@ public class UiThread /** * Executes something on UI thread after a given delayMillis. * - * @param task the code that must be executed on UI thread after given delayMillis. + * @param task the code that must be executed on UI thread after given delayMillis. * @param delayMillis The delayMillis until the code will be executed. */ public static void runLater(Runnable task, long delayMillis) @@ -56,4 +58,14 @@ public class UiThread { sUiHandler.removeCallbacks(task); } + + // Called from JNI. + @Keep + @SuppressWarnings("unused") + private static void forwardToMainThread(final long taskPointer) + { + runLater(() -> nativeProcessTask(taskPointer), 0); + } + + private static native void nativeProcessTask(long taskPointer); }