| 166 | } |
| 167 | |
| 168 | void log_to_kotlin_bridge(ggml_log_level level, const char *message) { |
| 169 | if (!g_jvm || !g_llama_android_class || !g_log_from_native_method) { |
| 170 | __android_log_print(ANDROID_LOG_DEBUG, "llama.cpp", "%s", message); |
| 171 | return; |
| 172 | } |
| 173 | |
| 174 | JNIEnv *env = nullptr; |
| 175 | bool did_attach_thread = false; |
| 176 | |
| 177 | jint get_env_result = g_jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6); |
| 178 | if (get_env_result == JNI_EDETACHED) { |
| 179 | if (attach_current_thread(g_jvm, &env) != JNI_OK || !env) { |
| 180 | __android_log_print(ANDROID_LOG_ERROR, TAG, "AttachCurrentThread failed"); |
| 181 | return; |
| 182 | } |
| 183 | did_attach_thread = true; |
| 184 | } else if (get_env_result != JNI_OK) { |
| 185 | __android_log_print(ANDROID_LOG_ERROR, TAG, "GetEnv failed"); |
| 186 | return; |
| 187 | } |
| 188 | |
| 189 | jstring jni_message = new_jstring_utf8(env, message); |
| 190 | if (jni_message == nullptr) { |
| 191 | // Handle potential out-of-memory error |
| 192 | if (did_attach_thread) { |
| 193 | g_jvm->DetachCurrentThread(); |
| 194 | } |
| 195 | return; |
| 196 | } |
| 197 | |
| 198 | env->CallStaticVoidMethod(g_llama_android_class, g_log_from_native_method, (jint) level, |
| 199 | jni_message); |
| 200 | env->DeleteLocalRef(jni_message); |
| 201 | |
| 202 | // ✨ THE FIX: Only detach the thread if we were the ones who attached it. |
| 203 | // In the case of the Llm-RunLoop, we will NOT detach it. |
| 204 | if (did_attach_thread) { |
| 205 | g_jvm->DetachCurrentThread(); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | void log_info_to_kt(const char *fmt, ...) { |
| 210 | char buffer[1024]; |
no test coverage detected