Report native Android database cleanup failures accurately
This commit is contained in:
1 parent
b8e7b18937
commit
3b42547740
3 files changed
+84
-13
No files matched your search
@@ -2,6 +2,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/mem.h"
|
||||
@@ -78,6 +79,47 @@ static int check_bridge_config(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Настоящий unlink: все три файла, повторное удаление, ошибка одного пути и восстановление после неё. */
|
||||
static int check_database_cleanup(const char* directory) {
|
||||
REQUIRE(utun_bridge_clear_database(NULL) == -1);
|
||||
REQUIRE(utun_bridge_clear_database("") == -1);
|
||||
REQUIRE(!utun_bridge_clear_database(directory));
|
||||
const char* names[] = {"chats.db", "chats.db-wal", "chats.db-shm"};
|
||||
char path[1024];
|
||||
for (unsigned i = 0; i < 3; ++i) {
|
||||
snprintf(path, sizeof(path), "%s/%s", directory, names[i]);
|
||||
FILE* file = fopen(path, "wb"); REQUIRE(file);
|
||||
int written = fputs("fixture", file);
|
||||
int closed = fclose(file);
|
||||
REQUIRE(written >= 0 && !closed);
|
||||
}
|
||||
REQUIRE(!utun_bridge_clear_database(directory));
|
||||
for (unsigned i = 0; i < 3; ++i) {
|
||||
snprintf(path, sizeof(path), "%s/%s", directory, names[i]);
|
||||
REQUIRE(test_unlink(path) == -1 && errno == ENOENT);
|
||||
}
|
||||
REQUIRE(!utun_bridge_clear_database(directory));
|
||||
snprintf(path, sizeof(path), "%s/chats.db-wal", directory);
|
||||
REQUIRE(!utun_mkdir(path, 0700));
|
||||
for (unsigned i = 0; i < 3; i += 2) {
|
||||
snprintf(path, sizeof(path), "%s/%s", directory, names[i]);
|
||||
FILE* file = fopen(path, "wb"); REQUIRE(file);
|
||||
int written = fputs("fixture", file);
|
||||
int closed = fclose(file);
|
||||
REQUIRE(written >= 0 && !closed);
|
||||
}
|
||||
REQUIRE(utun_bridge_clear_database(directory) == -1);
|
||||
for (unsigned i = 0; i < 3; i += 2) {
|
||||
snprintf(path, sizeof(path), "%s/%s", directory, names[i]);
|
||||
REQUIRE(test_unlink(path) == -1 && errno == ENOENT);
|
||||
}
|
||||
snprintf(path, sizeof(path), "%s/chats.db-wal", directory);
|
||||
REQUIRE(!test_rmdir(path));
|
||||
REQUIRE(!utun_bridge_clear_database(directory));
|
||||
printf("[PASS] database cleanup: exact files, missing files, real unlink failure and retry\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Один и тот же файл декодируется покадрово и батчами: PCM и количество отсчётов должны совпасть. */
|
||||
static int check_voice_batches(const char* path, int rate, int channels) {
|
||||
int frame = rate / 50 * channels, count = frame * 27;
|
||||
@@ -129,8 +171,12 @@ int main(void) {
|
||||
/* Проверки bridge требуют исправного владения таблицей провайдера. */
|
||||
if (!failed) failed += check_bridge_config();
|
||||
utun_config_set_provider(NULL);
|
||||
char directory[512] = "/tmp/utun_android_bridge_XXXXXX", path[1024];
|
||||
char directory[512], path[1024];
|
||||
const char* temporary = getenv("TMPDIR");
|
||||
int length = snprintf(directory, sizeof(directory), "%s/utun_android_bridge_XXXXXX", temporary ? temporary : "/tmp");
|
||||
REQUIRE(length > 0 && length < (int)sizeof(directory));
|
||||
REQUIRE(!test_mkdtemp(directory));
|
||||
failed += check_database_cleanup(directory);
|
||||
snprintf(path, sizeof(path), "%s/voice.opus", directory);
|
||||
const int rates[] = {8000, 12000, 16000, 24000, 48000};
|
||||
for (unsigned i = 0; i < sizeof(rates) / sizeof(rates[0]); i++)
|
||||
|
||||
@@ -51,7 +51,8 @@
|
||||
#include <strings.h>
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "../../../lib/platform_compat.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
@@ -176,6 +177,35 @@ void utun_bridge_destroy(void) {
|
||||
bridge_log(BLEV_INFO, "bridge destroy");
|
||||
}
|
||||
|
||||
/* Удалять только после остановки ядра: отсутствие файла нормально, остальные ошибки не скрывать. */
|
||||
int utun_bridge_clear_database(const char* db_path) {
|
||||
if (!db_path || !db_path[0]) { bridge_log(BLEV_ERROR, "clearDatabase: no db path"); return -1; }
|
||||
const char* names[] = {"chats.db", "chats.db-wal", "chats.db-shm"};
|
||||
size_t length = strlen(db_path);
|
||||
if (length > SIZE_MAX - sizeof("/chats.db-wal")) {
|
||||
bridge_log(BLEV_ERROR, "clearDatabase: path length overflow bytes=%zu", length); return -1;
|
||||
}
|
||||
size_t capacity = length + sizeof("/chats.db-wal");
|
||||
char* path = u_malloc(capacity);
|
||||
if (!path) { bridge_log(BLEV_ERROR, "clearDatabase: path allocation failed bytes=%zu", capacity); return -1; }
|
||||
unsigned removed = 0, missing = 0, failed = 0;
|
||||
for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); ++i) {
|
||||
snprintf(path, capacity, "%s/%s", db_path, names[i]);
|
||||
if (!unlink(path)) removed++;
|
||||
else {
|
||||
int error = errno;
|
||||
if (error == ENOENT) missing++;
|
||||
else {
|
||||
failed++;
|
||||
bridge_log(BLEV_ERROR, "clearDatabase: unlink failed path=%s errno=%d: %s", path, error, strerror(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
u_free(path);
|
||||
bridge_log(failed ? BLEV_WARN : BLEV_INFO, "clearDatabase: path=%s removed=%u missing=%u failed=%u", db_path, removed, missing, failed);
|
||||
return failed ? -1 : 0;
|
||||
}
|
||||
|
||||
int utun_bridge_start(const char* config_text) {
|
||||
bridge_log(BLEV_INFO, "bridge start: launching utun instance");
|
||||
int rc = instance_lite_start(config_text);
|
||||
@@ -2462,17 +2492,7 @@ JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeRegenerateKeys(
|
||||
JNIEXPORT jboolean JNICALL Java_com_utun_chat_data_NativeLib_nativeClearDatabase(
|
||||
JNIEnv* env, jobject thiz) {
|
||||
(void)env; (void)thiz;
|
||||
if (!g_db_path[0]) {
|
||||
bridge_log(BLEV_ERROR, "clearDatabase: no db path");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
char db_file[512], wal_file[512], shm_file[512];
|
||||
snprintf(db_file, sizeof(db_file), "%s/chats.db", g_db_path);
|
||||
snprintf(wal_file, sizeof(wal_file), "%s/chats.db-wal", g_db_path);
|
||||
snprintf(shm_file, sizeof(shm_file), "%s/chats.db-shm", g_db_path);
|
||||
unlink(db_file); unlink(wal_file); unlink(shm_file);
|
||||
bridge_log(BLEV_INFO, "clearDatabase: deleted DB files at %s", g_db_path);
|
||||
return JNI_TRUE;
|
||||
return utun_bridge_clear_database(g_db_path) == 0 ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
/* ── Voice recording JNI ── */
|
||||
|
||||
@@ -54,6 +54,11 @@ bool utun_bridge_init(const char* db_path, int control_port,
|
||||
* Готовность сервисов — CHAT_EVT_SERVICE_STARTED, а не возврат start. */
|
||||
int utun_bridge_start(const char* config_text);
|
||||
|
||||
/* После полного stop, без параллельного start: удалить chats.db и его -wal/-shm из db_path.
|
||||
* db_path — непустой каталог. 0 — все файлы удалены/уже отсутствуют; -1 — неверный путь, память либо ошибка IO.
|
||||
* При частичном отказе проверяет остальные файлы; каждую ошибку и итоговые счётчики пишет в лог. */
|
||||
int utun_bridge_clear_database(const char* db_path);
|
||||
|
||||
/* Освободить recorder, вызвать instance_lite_stop и снять C log/config callbacks.
|
||||
* Config-provider сбрасывается к defaults; повторный init начинает новую регистрацию.
|
||||
* Перед вызовом остановить внешние media workers/DSP; ограничения ожидания — instance_lite.h.
|
||||
|
||||
Reference in new issue
Block a user