Contain JNI config failures and validate audio result buffers
This commit is contained in:
1 parent
af776deed6
commit
20f506fc3c
3 files changed
+51
-14
No files matched your search
@@ -7,6 +7,7 @@
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../src/utun_instance.h"
|
||||
#include "../src/chat/chat_core.h"
|
||||
#include "../src/chat/chat_core_priv.h"
|
||||
#include "../src/chat/chat_event.h"
|
||||
#include "../src/dm/dm_core.h"
|
||||
#include "../src/dm/dm_crypto.h"
|
||||
|
||||
@@ -72,6 +72,10 @@ UTUN-сервис включается отдельно через `[gui] utun_e
|
||||
Реестры команд освобождают также PCM/compressor и собственные cache-файлы при отмене до исполнения.
|
||||
JNI строки преобразуются через обычный UTF-8 byte[] в обе стороны: имена, JSON и пути сохраняют emoji.
|
||||
NUL во входной строке отклоняется, ошибки выделения возвращают NULL/отказ, а не усечённую строку.
|
||||
SQL/память в channels/messages/members возвращает NULL, отдельно от подтверждённого пустого массива.
|
||||
Массивы сокетов/линков строятся целиком с экранированием имён; при ошибке прежний UI-снимок сохраняется.
|
||||
JNI event callback удерживает local ref на время вызова, независимо от замены global ref.
|
||||
Ошибка копирования не доставляет повреждённый payload; исключение callback описывается/снимается для следующих событий.
|
||||
Заимствованные inst/ua не удерживают ресурс; они пригодны только в потоке владельца.
|
||||
`instance_lite_post` публикует команду под защитой времени жизни worker и заполняет её поле instance.
|
||||
Аргумент принадлежит callback, а при отмене — discard; отдельный реестр переживает удаление posted_task.
|
||||
|
||||
@@ -176,6 +176,7 @@ int utun_bridge_destroy(void) {
|
||||
voice_recorder_deinit();
|
||||
utun_config_set_provider(NULL);
|
||||
__atomic_store_n(&g_on_log, NULL, __ATOMIC_RELEASE);
|
||||
g_on_event = NULL;
|
||||
g_cfg_string = NULL;
|
||||
g_cfg_int64 = NULL;
|
||||
g_cfg_int = NULL;
|
||||
@@ -1835,25 +1836,47 @@ void instance_event_handler(int type, const uint8_t* data, int len) {
|
||||
static jstring jni_get_string_callback(JNIEnv* env, const char* key) {
|
||||
if (!g_config_callback) return NULL;
|
||||
jclass cls = (*env)->GetObjectClass(env, g_config_callback);
|
||||
jmethodID mid = (*env)->GetMethodID(env, cls, "getString", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
if (!mid) return NULL;
|
||||
jstring jkey = jni_text(env, key);
|
||||
jstring result = (jstring)(*env)->CallObjectMethod(env, g_config_callback, mid, jkey);
|
||||
(*env)->DeleteLocalRef(env, jkey);
|
||||
jmethodID mid = cls ? (*env)->GetMethodID(env, cls, "getString", "(Ljava/lang/String;)Ljava/lang/String;") : NULL;
|
||||
jstring jkey = mid ? jni_text(env, key) : NULL;
|
||||
jstring result = jkey ? (jstring)(*env)->CallObjectMethod(env, g_config_callback, mid, jkey) : NULL;
|
||||
if (jkey) (*env)->DeleteLocalRef(env, jkey);
|
||||
if (cls) (*env)->DeleteLocalRef(env, cls);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char* jni_cfg_get_string(const char* key) {
|
||||
JNIEnv* env = NULL;
|
||||
if (!g_jvm || (*g_jvm)->GetEnv(g_jvm, (void**)&env, JNI_VERSION_1_6) != JNI_OK)
|
||||
return NULL;
|
||||
static __thread char buf[4096];
|
||||
buf[0] = 0;
|
||||
if (!g_jvm) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "JNI config: JVM unavailable"); return NULL; }
|
||||
int attached = 0;
|
||||
jint rc = (*g_jvm)->GetEnv(g_jvm, (void**)&env, JNI_VERSION_1_6);
|
||||
if (rc == JNI_EDETACHED) {
|
||||
rc = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
|
||||
if (rc == JNI_OK) attached = 1;
|
||||
}
|
||||
if (rc != JNI_OK) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "JNI config: attach/GetEnv failed rc=%d", rc); return NULL; }
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "JNI config: preserving existing exception key=%s", key); goto finish;
|
||||
}
|
||||
jstring js = jni_get_string_callback(env, key);
|
||||
if (!js) return NULL;
|
||||
const char* result = jni_utf8(env, js);
|
||||
static char buf[256];
|
||||
snprintf(buf, sizeof(buf), "%s", result ? result : "");
|
||||
if (result) u_free((void*)result);
|
||||
(*env)->DeleteLocalRef(env, js);
|
||||
if (js && !(*env)->ExceptionCheck(env)) {
|
||||
char* result = jni_utf8(env, js);
|
||||
if (result) {
|
||||
size_t length = strlen(result);
|
||||
if (length < sizeof(buf)) memcpy(buf, result, length + 1);
|
||||
else __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "JNI config: value too long key=%s bytes=%zu", key, length);
|
||||
u_free(result);
|
||||
}
|
||||
}
|
||||
if (js) (*env)->DeleteLocalRef(env, js);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "JNI config: callback failed key=%s", key);
|
||||
(*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env);
|
||||
}
|
||||
finish:
|
||||
if (attached && (*g_jvm)->DetachCurrentThread(g_jvm) != JNI_OK)
|
||||
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "JNI config: detach failed key=%s", key);
|
||||
return buf[0] ? buf : NULL;
|
||||
}
|
||||
|
||||
@@ -2027,6 +2050,7 @@ JNIEXPORT jlong JNICALL Java_com_utun_chat_data_NativeLib_nativeDeriveNodeId(
|
||||
jsize pk_len = (*env)->GetArrayLength(env, pubkey);
|
||||
if (pk_len < 32) return 0;
|
||||
uint8_t* pk = (uint8_t*)(*env)->GetByteArrayElements(env, pubkey, NULL);
|
||||
if (!pk) { bridge_log(BLEV_ERROR, "Node ID: public key JNI access failed"); return 0; }
|
||||
uint64_t node_id = sc_derive_node_id_from_pubkey(pk);
|
||||
(*env)->ReleaseByteArrayElements(env, pubkey, (jbyte*)pk, JNI_ABORT);
|
||||
return (jlong)node_id;
|
||||
@@ -2568,6 +2592,7 @@ JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeVoiceFeed(
|
||||
if (!samples) return JNI_FALSE;
|
||||
jsize len = (*env)->GetArrayLength(env, samples);
|
||||
jshort* data = (*env)->GetShortArrayElements(env, samples, NULL);
|
||||
if (!data) { bridge_log(BLEV_ERROR, "Voice capture: JNI PCM access failed"); return JNI_FALSE; }
|
||||
int rc = utun_bridge_voice_feed((const int16_t*)data, (int)len);
|
||||
(*env)->ReleaseShortArrayElements(env, samples, data, JNI_ABORT);
|
||||
return (rc == 0) ? JNI_TRUE : JNI_FALSE;
|
||||
@@ -2689,13 +2714,18 @@ JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativePhotoSend(
|
||||
JNIEXPORT jlong JNICALL Java_com_utun_chat_data_NativeLib_nativeVoiceDecodeOpen(
|
||||
JNIEnv* env, jobject thiz, jstring filePath, jintArray outInfo) {
|
||||
(void)thiz;
|
||||
if (!filePath || !outInfo) return 0;
|
||||
if (!filePath || !outInfo || (*env)->GetArrayLength(env, outInfo) < 3) {
|
||||
bridge_log(BLEV_ERROR, "Voice decode: expected path and IntArray(3)"); return 0;
|
||||
}
|
||||
const char* fp = jni_utf8(env, filePath);
|
||||
int sr = 0, ch = 0, total = 0;
|
||||
void* h = utun_bridge_voice_decode_open(fp, &sr, &ch, &total);
|
||||
if (h) {
|
||||
jint info[3] = {sr, ch, total};
|
||||
(*env)->SetIntArrayRegion(env, outInfo, 0, 3, info);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
bridge_log(BLEV_ERROR, "Voice decode: output metadata JNI copy failed"); utun_bridge_voice_decode_close(h); h = NULL;
|
||||
}
|
||||
}
|
||||
if (fp) u_free((void*)fp);
|
||||
return (jlong)(intptr_t)h;
|
||||
@@ -2707,6 +2737,7 @@ JNIEXPORT jint JNICALL Java_com_utun_chat_data_NativeLib_nativeVoiceDecodeRead(
|
||||
if (handle == 0 || !buf) return -1;
|
||||
jsize max = (*env)->GetArrayLength(env, buf);
|
||||
jshort* data = (*env)->GetShortArrayElements(env, buf, NULL);
|
||||
if (!data) { bridge_log(BLEV_ERROR, "Voice decode: JNI PCM buffer access failed"); return -1; }
|
||||
int read = utun_bridge_voice_decode_read((void*)(intptr_t)handle, (int16_t*)data, (int)max);
|
||||
(*env)->ReleaseShortArrayElements(env, buf, data, 0);
|
||||
return (jint)read;
|
||||
@@ -2971,6 +3002,7 @@ JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeCallAudioFeed
|
||||
}
|
||||
jsize len = (*env)->GetArrayLength(env, samples);
|
||||
jshort* data = (*env)->GetShortArrayElements(env, samples, NULL);
|
||||
if (!data) { bridge_log(BLEV_ERROR, "Radio capture: JNI PCM access failed"); return JNI_FALSE; }
|
||||
if (!data) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "call capture: JNI PCM access failed");
|
||||
return JNI_FALSE;
|
||||
|
||||
Reference in new issue
Block a user