Skip to content

Commit

Permalink
Introduce non-droppable control messages
Browse files Browse the repository at this point in the history
Control messages are queued from the main thread and sent to the device
from a separate thread.

When the queue is full, messages are just dropped. This avoids to
accumulate too much delay between the client and the device in case of
network issue.

However, some messages should not be dropped: for example, dropping a
UHID_CREATE message would make all further UHID_INPUT messages invalid.
Therefore, mark these messages as non-droppable.

A non-droppable event is queued anyway (resizing the queue if
necessary, unless the allocation fails).

PR Genymobile#5270 <Genymobile#5270>
  • Loading branch information
rom1v committed Sep 15, 2024
1 parent a84b0df commit 49c8ca3
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 6 deletions.
7 changes: 7 additions & 0 deletions app/src/control_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,13 @@ sc_control_msg_log(const struct sc_control_msg *msg) {
}
}

bool
sc_control_msg_is_droppable(const struct sc_control_msg *msg) {
// Cannot drop UHID_CREATE messages, because it would cause all further
// UHID_INPUT messages for this device to be invalid
return msg->type != SC_CONTROL_MSG_TYPE_UHID_CREATE;
}

void
sc_control_msg_destroy(struct sc_control_msg *msg) {
switch (msg->type) {
Expand Down
5 changes: 5 additions & 0 deletions app/src/control_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, uint8_t *buf);
void
sc_control_msg_log(const struct sc_control_msg *msg);

// Even when the buffer is "full", some messages must absolutely not be dropped
// to avoid inconsistencies.
bool
sc_control_msg_is_droppable(const struct sc_control_msg *msg);

void
sc_control_msg_destroy(struct sc_control_msg *msg);

Expand Down
26 changes: 20 additions & 6 deletions app/src/controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

#include "util/log.h"

#define SC_CONTROL_MSG_QUEUE_MAX 64
// Drop droppable events above this limit
#define SC_CONTROL_MSG_QUEUE_LIMIT 60

static void
sc_controller_receiver_on_ended(struct sc_receiver *receiver, bool error,
Expand All @@ -22,7 +23,9 @@ sc_controller_init(struct sc_controller *controller, sc_socket control_socket,
void *cbs_userdata) {
sc_vecdeque_init(&controller->queue);

bool ok = sc_vecdeque_reserve(&controller->queue, SC_CONTROL_MSG_QUEUE_MAX);
// Add 4 to support 4 non-droppable events without re-allocation
bool ok = sc_vecdeque_reserve(&controller->queue,
SC_CONTROL_MSG_QUEUE_LIMIT + 4);
if (!ok) {
return false;
}
Expand Down Expand Up @@ -93,20 +96,31 @@ sc_controller_push_msg(struct sc_controller *controller,
sc_control_msg_log(msg);
}

bool pushed = false;

sc_mutex_lock(&controller->mutex);
bool full = sc_vecdeque_is_full(&controller->queue);
if (!full) {
size_t size = sc_vecdeque_size(&controller->queue);
if (size < SC_CONTROL_MSG_QUEUE_LIMIT) {
bool was_empty = sc_vecdeque_is_empty(&controller->queue);
sc_vecdeque_push_noresize(&controller->queue, *msg);
pushed = true;
if (was_empty) {
sc_cond_signal(&controller->msg_cond);
}
} else if (!sc_control_msg_is_droppable(msg)) {
bool ok = sc_vecdeque_push(&controller->queue, *msg);
if (ok) {
pushed = true;
} else {
// A non-droppable event must be dropped anyway
LOG_OOM();
}
}
// Otherwise (if the queue is full), the msg is discarded
// Otherwise, the msg is discarded

sc_mutex_unlock(&controller->mutex);

return !full;
return pushed;
}

static bool
Expand Down

0 comments on commit 49c8ca3

Please sign in to comment.