Verify Android DM commit results and document sensor cleanup retry
This commit is contained in:
1 parent
96166cd3a7
commit
f5405cdb3d
2 files changed
+52
No files matched your search
@@ -8,6 +8,8 @@
|
||||
#include "../src/utun_instance.h"
|
||||
#include "../src/chat/chat_core.h"
|
||||
#include "../src/chat/chat_event.h"
|
||||
#include "../src/dm/dm_core.h"
|
||||
#include "../src/transport_layer/secure_channel.h"
|
||||
#include "../src/media_async/attachment_send.h"
|
||||
#include "../src/media_async/encrypted_file.h"
|
||||
#include "../src/routing_layer/topo_node_sqlite.h"
|
||||
@@ -191,6 +193,47 @@ static int check_local_sockets(void) {
|
||||
u_free(json); return 0;
|
||||
}
|
||||
|
||||
/* Android PM ждёт commit, а отказ очереди не создаёт ожидание события; текст сохраняет обычный UTF-8. */
|
||||
static int check_dm_submissions(void) {
|
||||
struct SC_MYKEYS peer; uint8_t ed[32];
|
||||
REQUIRE(!sc_generate_keypair(&peer) && !sc_derive_ed25519_pubkey(peer.private_key, ed));
|
||||
uint64_t node = sc_derive_node_id_from_pubkey(peer.public_key);
|
||||
sqlite3_stmt* st = NULL;
|
||||
REQUIRE(sqlite3_prepare_v2(instance->topo_sqlite_db,
|
||||
"INSERT INTO nodes(node_id,x25519_pubkey,ed25519_pubkey,name) VALUES(?,?,?,'Android PM peer')", -1, &st, NULL) == SQLITE_OK);
|
||||
sqlite3_bind_int64(st, 1, (sqlite3_int64)node);
|
||||
sqlite3_bind_blob(st, 2, peer.public_key, 32, SQLITE_STATIC); sqlite3_bind_blob(st, 3, ed, 32, SQLITE_STATIC);
|
||||
int rc = sqlite3_step(st); sqlite3_finalize(st); REQUIRE(rc == SQLITE_DONE);
|
||||
REQUIRE(!dm_start(instance, node, peer.public_key, ed, "Android PM peer", NULL));
|
||||
char conv[64], before[8192], after[8192], value[256]; size_t length = 0;
|
||||
snprintf(conv, sizeof(conv), "%llu", (unsigned long long)dm_derive_conv_id(instance->node_id, node));
|
||||
uint64_t generation = dm_history_generation(instance, conv); REQUIRE(generation);
|
||||
const uint8_t text[] = "Привет 😀 \"PM\"\nследующая строка";
|
||||
REQUIRE(!utun_bridge_dm_send(conv, text, sizeof(text) - 1, generation, 11) && wait_result(11) == 1);
|
||||
REQUIRE(!dm_list_messages_json(instance, conv, 20, 0, before, sizeof(before), &length));
|
||||
REQUIRE(!extract(before, "$[0].data", value, sizeof(value)) && !strcmp(value, (const char*)text));
|
||||
REQUIRE(!utun_bridge_dm_send(conv, text, sizeof(text) - 1, generation + 1, 12) && wait_result(12) == -1);
|
||||
REQUIRE(sqlite3_exec(instance->topo_sqlite_db, "CREATE TEMP TRIGGER android_dm_write_fail BEFORE INSERT ON dm_outbox"
|
||||
" BEGIN SELECT RAISE(FAIL,'android fixture write failure'); END", NULL, NULL, NULL) == SQLITE_OK);
|
||||
REQUIRE(!utun_bridge_dm_send(conv, text, sizeof(text) - 1, generation, 13) && wait_result(13) == -1);
|
||||
REQUIRE(sqlite3_exec(instance->topo_sqlite_db, "DROP TRIGGER android_dm_write_fail", NULL, NULL, NULL) == SQLITE_OK);
|
||||
REQUIRE(!dm_list_messages_json(instance, conv, 20, 0, after, sizeof(after), &length) && !strcmp(before, after));
|
||||
REQUIRE(!utun_bridge_dm_send(conv, text, sizeof(text) - 1, generation, 14) && wait_result(14) == 1);
|
||||
const uint8_t embedded_nul[] = {'a', 0, 'b'};
|
||||
REQUIRE(utun_bridge_dm_send(conv, embedded_nul, sizeof(embedded_nul), generation, 15) == -1);
|
||||
REQUIRE(utun_bridge_dm_send(conv, text, 0, generation, 15) == -1);
|
||||
REQUIRE(utun_bridge_dm_send(conv, text, sizeof(text) - 1, 0, 15) == -1);
|
||||
REQUIRE(utun_bridge_dm_send(conv, text, sizeof(text) - 1, generation, 0) == -1);
|
||||
uint8_t oversized[DM_DATA_MAX + 1] = {0};
|
||||
REQUIRE(utun_bridge_dm_send(conv, oversized, sizeof(oversized), generation, 16) == -1);
|
||||
struct UTUN_INSTANCE* saved = instance; instance = NULL;
|
||||
rc = utun_bridge_dm_send(conv, text, sizeof(text) - 1, generation, 17); instance = saved;
|
||||
REQUIRE(rc == -1);
|
||||
uasync_poll(async, 0); REQUIRE(!results[15] && !results[16] && !results[17]);
|
||||
printf("[PASS] Android PM: UTF-8, commit ACK, stale generation, SQL rollback/retry and rejected requests\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN);
|
||||
char directory[512] = "/tmp/utun_android_replies_XXXXXX", config[1024], channel[64], hex[65];
|
||||
@@ -206,6 +249,7 @@ int main(void) {
|
||||
REQUIRE(!extract(json, "$[0].id", channel, sizeof(channel))); u_free(json);
|
||||
REQUIRE(!check_addresses(channel));
|
||||
REQUIRE(!check_local_sockets());
|
||||
REQUIRE(!check_dm_submissions());
|
||||
uint8_t empty[32] = {0}, original[32], missing[32]; memset(missing, 0xff, sizeof(missing));
|
||||
REQUIRE(!utun_bridge_send_message(channel, "Привет 😀 \"original\"\nnext line", empty, 1) && wait_result(1) == 1);
|
||||
json = utun_bridge_get_messages_json(channel, 1, NULL, 0);
|
||||
|
||||
@@ -245,6 +245,9 @@ ConversationComposer сохраняет draft, URI и тип вложения ч
|
||||
показывается ресурсом интерфейса; ошибка cleanup логируется отдельно.
|
||||
SAF export в канале и PM сообщает об отказе запуска picker/записи. Null output stream
|
||||
не считается успешным сохранением; ожидающий путь переживает пересоздание Activity.
|
||||
PM text передаётся JNI как обычные UTF-8 bytes, generation и ненулевой request ID.
|
||||
Успешный enqueue не очищает draft: composer ждёт MSG_SUBMITTED после транзакции истории/outbox.
|
||||
При stale generation/SQL error draft остаётся, отказ очереди завершает ожидание сразу.
|
||||
|
||||
Звонок и рация используют общий C голосовой стек. Kotlin владеет AudioRecord/AudioTrack,
|
||||
feed/pull workers и маршрутом Android Telecom; DSP и сетевой сигналинг разделены.
|
||||
@@ -283,6 +286,11 @@ target. Detach/close продолжают освобождение незави
|
||||
через 250 мс..30 с. При отказе Handler повторный release завершает её явно.
|
||||
|
||||
`CallAudioRouter` сохраняет device callback и каждый полученный Bluetooth proxy до
|
||||
успешного unregister/close. ProximityManager также сохраняет прежний sensor listener
|
||||
и его manager при отказе unregister: start ждёт cleanup, Handler повторяет его через
|
||||
250 мс..30 с, повторный stop работает после отказа таймера. Старая регистрация и
|
||||
повреждённые показания не дают ложного FAR; после lookup failure start повторяет поиск.
|
||||
CallAudioRouter ждёт
|
||||
успешного unregister/close. stop инвалидирует callbacks и снимки устройств сразу,
|
||||
очищает независимые ресурсы и бросает ошибку при неподтверждённом результате.
|
||||
Собственные communication device/SCO-заявки отмечаются до API и снимаются отдельно;
|
||||
|
||||
Reference in new issue
Block a user