Own queued Android phone state data within the worker lifetime

This commit is contained in:
evgeny committed 2026-10-27 21:23:18 +01:00
1 parent 2b55d9225a
commit 067c1cd496
3 files changed
+51 -19

No files matched your search

@@ -1370,26 +1370,8 @@ int utun_bridge_set_active(int active) {
return instance_lite_set_active(active);
}
struct phone_state_request { struct UTUN_INSTANCE* inst; int state; unsigned policy; };
static void phone_state_execute(void* arg) {
struct phone_state_request* req = arg;
call_set_phone_state(req->inst, req->state, req->policy); u_free(req);
}
int utun_bridge_set_phone_state(int state, unsigned policy) {
struct UTUN_INSTANCE* inst = instance_lite_get_instance();
struct UASYNC* ua = instance_lite_get_uasync();
if (!inst || !ua || !uasync_is_running(ua) || state < 0 || state > 2 || policy > 31) {
DEBUG_WARN(DEBUG_CATEGORY_CALL, "phone state JNI unavailable state=%d policy=%u", state, policy); return -1;
}
struct phone_state_request* req = u_calloc(1, sizeof(*req));
struct posted_task* task = u_calloc(1, sizeof(*task));
if (!req || !task) {
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "phone state JNI allocation failed"); u_free(req); u_free(task); return -1;
}
req->inst = inst; req->state = state; req->policy = policy;
task->callback = phone_state_execute; task->arg = req; uasync_post_reserved(ua, task);
return 0;
return instance_lite_set_phone_state(state, policy);
}
static void bridge_notify_network_active_trampoline(void* arg) {
@@ -31,6 +31,7 @@
#include "../jni_bridge/android_jni_bridge.h"
#include "standby.h"
#include "stream_bridge.h"
#include "call/call.h"
#include "call/call_video_port.h"
#ifdef UTUN_WITH_VOICE
#include "call/call_audio.h"
@@ -716,6 +717,49 @@ int instance_lite_set_active(int active) {
return 0;
}
/* posted — первое поле: uasync освобождает всё выделение и после callback, и при отмене очереди. */
struct phone_state_task {
struct posted_task posted;
int state;
unsigned policy;
};
/* Только worker: request заимствован у исполняемой задачи, instance берём в момент применения. */
static void set_phone_state_trampoline(void* arg) {
const struct phone_state_task* request = arg;
struct UTUN_INSTANCE* inst = __atomic_load_n(&g_inst, __ATOMIC_ACQUIRE);
if (!inst || __atomic_load_n(&g_stop, __ATOMIC_ACQUIRE)) {
DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "Android phone state command cancelled: worker is stopping"); return;
}
call_set_phone_state(inst, request->state, request->policy);
DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "Android phone state applied state=%d policy=%u", request->state, request->policy);
}
int instance_lite_set_phone_state(int state, unsigned policy) {
if (state < 0 || state > 2 || policy > 31) {
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "Android phone state request invalid state=%d policy=%u", state, policy); return -1;
}
if (g_is_worker) {
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "Android phone state request refused: frontend thread required"); return -1;
}
pthread_mutex_lock(&g_stop_mutex);
struct UASYNC* ua = __atomic_load_n(&g_ua, __ATOMIC_ACQUIRE);
if (!ua || !__atomic_load_n(&g_running, __ATOMIC_ACQUIRE) || __atomic_load_n(&g_stop, __ATOMIC_ACQUIRE)) {
pthread_mutex_unlock(&g_stop_mutex);
DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "Android phone state request rejected: core is not ready"); return -1;
}
struct phone_state_task* request = u_malloc(sizeof(*request));
if (!request) {
pthread_mutex_unlock(&g_stop_mutex);
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "Android phone state request allocation failed"); return -1;
}
request->state = state; request->policy = policy;
request->posted.callback = set_phone_state_trampoline; request->posted.arg = request;
uasync_post_reserved(ua, &request->posted);
pthread_mutex_unlock(&g_stop_mutex);
return 0;
}
/* ── Лёгкое обновление сокетов (auto_sockets=android) ── */
static void update_sockets_trampoline(void* arg) {
@@ -71,6 +71,12 @@ int instance_lite_regenerate_keys(const char* config_text);
* При stop ожидающая команда может отмениться. Результат применения/stream hold логируется в потоке ядра. */
int instance_lite_set_active(int active);
/* Frontend: поставить состояние SIM (0 UNKNOWN/1 IDLE/2 BUSY) и маску call_policy (0..31) живому worker.
* 0 — данные скопированы в задачу под защитой времени жизни uasync; -1 — неверные аргументы/поток, неготовое ядро или OOM.
* Применение асинхронно в текущем ядре; stop/restart может отменить ожидающую команду, освободив её данные.
* После SERVICE_STARTED frontend повторно отправляет актуальные state/policy. */
int instance_lite_set_phone_state(int state, unsigned policy);
/* Копирует INI, будит poll-loop и пересоздаёт instance и uasync внутри worker.
* До остановки проверяет конфиг и сохраняет отсутствующие ключи; отказ оставляет прежнее ядро.
* При инициализации ставит запрос в очередь; при завершившемся worker делает join/start.