From 91dea41ca2119147f65e35c2b3ab25f827c97758 Mon Sep 17 00:00:00 2001 From: chinosk <2248589280@qq.com> Date: Mon, 24 Jun 2024 22:09:25 +0800 Subject: [PATCH] Add loop some devices may crash when using JNI callback in that way... --- app/src/main/cpp/GakumasLocalify/Log.cpp | 80 +++++++++++-------- app/src/main/cpp/GakumasLocalify/Log.h | 3 + app/src/main/cpp/libMarryKotone.cpp | 7 ++ .../gakumas/localify/GakumasHookMain.kt | 38 +++++++++ 4 files changed, 95 insertions(+), 33 deletions(-) diff --git a/app/src/main/cpp/GakumasLocalify/Log.cpp b/app/src/main/cpp/GakumasLocalify/Log.cpp index 0ac4db6..c857f36 100644 --- a/app/src/main/cpp/GakumasLocalify/Log.cpp +++ b/app/src/main/cpp/GakumasLocalify/Log.cpp @@ -4,6 +4,7 @@ #include #include #include +#include extern JavaVM* g_javaVM; extern jclass g_gakumasHookMainClass; @@ -24,9 +25,13 @@ extern jmethodID showToastMethodId; namespace GakumasLocal::Log { + namespace { + std::queue showingToasts{}; + } + std::string StringFormat(const char* fmt, ...) { GetParamStringResult(result); - return result.c_str(); + return result; } void Log(int prio, const char* msg) { @@ -70,38 +75,7 @@ namespace GakumasLocal::Log { __android_log_write(prio, "GakumasLog", result.c_str()); } - void ShowToast(const std::string& text) { - DebugFmt("Toast: %s", text.c_str()); - - std::thread([text](){ - auto env = Misc::GetJNIEnv(); - if (!env) { - return; - } - - jclass& kotlinClass = g_gakumasHookMainClass; - if (!kotlinClass) { - g_javaVM->DetachCurrentThread(); - return; - } - jmethodID& methodId = showToastMethodId; - if (!methodId) { - g_javaVM->DetachCurrentThread(); - return; - } - jstring param = env->NewStringUTF(text.c_str()); - env->CallStaticVoidMethod(kotlinClass, methodId, param); - - g_javaVM->DetachCurrentThread(); - }).detach(); - } - - void ShowToastFmt(const char* fmt, ...) { - GetParamStringResult(result); - ShowToast(result); - } - - void ShowToast(const char* text) { + void ShowToastJNI(const char* text) { DebugFmt("Toast: %s", text); std::thread([text](){ @@ -126,4 +100,44 @@ namespace GakumasLocal::Log { g_javaVM->DetachCurrentThread(); }).detach(); } + + + void ShowToast(const std::string& text) { + showingToasts.push(text); + } + + void ShowToast(const char* text) { + DebugFmt("Toast: %s", text); + return ShowToast(std::string(text)); + } + + void ShowToastFmt(const char* fmt, ...) { + GetParamStringResult(result); + ShowToast(result); + } + + std::string GetQueuedToast() { + if (showingToasts.empty()) { + return ""; + } + const auto ret = showingToasts.front(); + showingToasts.pop(); + return ret; + } + + void ToastLoop(JNIEnv *env, jclass clazz) { + const auto toastString = GetQueuedToast(); + if (toastString.empty()) return; + + static auto _showToastMethodId = env->GetStaticMethodID(clazz, "showToast", "(Ljava/lang/String;)V"); + + if (env && clazz && _showToastMethodId) { + jstring param = env->NewStringUTF(toastString.c_str()); + env->CallStaticVoidMethod(clazz, _showToastMethodId, param); + env->DeleteLocalRef(param); + } + else { + _showToastMethodId = env->GetStaticMethodID(clazz, "showToast", "(Ljava/lang/String;)V"); + } + } } diff --git a/app/src/main/cpp/GakumasLocalify/Log.h b/app/src/main/cpp/GakumasLocalify/Log.h index 429f886..d01c2eb 100644 --- a/app/src/main/cpp/GakumasLocalify/Log.h +++ b/app/src/main/cpp/GakumasLocalify/Log.h @@ -2,6 +2,7 @@ #define GAKUMAS_LOCALIFY_LOG_H #include +#include namespace GakumasLocal::Log { std::string StringFormat(const char* fmt, ...); @@ -16,6 +17,8 @@ namespace GakumasLocal::Log { void ShowToast(const char* text); void ShowToastFmt(const char* fmt, ...); + + void ToastLoop(JNIEnv *env, jclass clazz); } #endif //GAKUMAS_LOCALIFY_LOG_H diff --git a/app/src/main/cpp/libMarryKotone.cpp b/app/src/main/cpp/libMarryKotone.cpp index 5717925..d63b360 100644 --- a/app/src/main/cpp/libMarryKotone.cpp +++ b/app/src/main/cpp/libMarryKotone.cpp @@ -111,4 +111,11 @@ Java_io_github_chinosk_gakumas_localify_GakumasHookMain_loadConfig(JNIEnv *env, const auto configJsonStrChars = env->GetStringUTFChars(config_json_str, nullptr); const std::string configJson = configJsonStrChars; GakumasLocal::Config::LoadConfig(configJson); +} + +extern "C" +JNIEXPORT void JNICALL +Java_io_github_chinosk_gakumas_localify_GakumasHookMain_pluginCallbackLooper(JNIEnv *env, + jclass clazz) { + GakumasLocal::Log::ToastLoop(env, clazz); } \ No newline at end of file diff --git a/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt b/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt index 5a54699..31fcbd1 100644 --- a/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt +++ b/app/src/main/java/io/github/chinosk/gakumas/localify/GakumasHookMain.kt @@ -25,8 +25,14 @@ import android.widget.Toast import com.google.gson.Gson import de.robv.android.xposed.XposedBridge import io.github.chinosk.gakumas.localify.models.GakumasConfig +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch import java.io.File import java.util.Locale +import kotlin.system.measureTimeMillis val TAG = "GakumasLocalify" @@ -42,6 +48,20 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { private var getConfigError: Exception? = null override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { +// if (lpparam.packageName == "io.github.chinosk.gakumas.localify") { +// XposedHelpers.findAndHookMethod( +// "io.github.chinosk.gakumas.localify.MainActivity", +// lpparam.classLoader, +// "showToast", +// String::class.java, +// object : XC_MethodHook() { +// override fun beforeHookedMethod(param: MethodHookParam) { +// Log.d(TAG, "beforeHookedMethod hooked: ${param.args}") +// } +// } +// ) +// } + if (lpparam.packageName != targetPackageName) { return } @@ -175,6 +195,21 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { alreadyInitialized = true } }) + + startLoop() + } + + @OptIn(DelicateCoroutinesApi::class) + private fun startLoop() { + GlobalScope.launch { + val interval = 1000L / 30 + while (isActive) { + val timeTaken = measureTimeMillis { + pluginCallbackLooper() + } + delay(interval - timeTaken) + } + } } fun initGkmsConfig(activity: Activity) { @@ -337,6 +372,9 @@ class GakumasHookMain : IXposedHookLoadPackage, IXposedHookZygoteInit { Log.e(TAG, "showToast: $message failed: applicationContext is null") } } + + @JvmStatic + external fun pluginCallbackLooper() } init {